Skip to content

nullstone-config-files

Teaches Claude to produce schema-valid .nullstone/*.yml files with a consistent style, resolving unknown modules via the Nullstone MCP before emitting blocks.

Catalog version this page describes: v0.1.0 (source)

Triggers

Claude invokes this skill when:

  • You edit any YAML under .nullstone/ — single-stack or multi-stack.
  • You create a new .nullstone/ directory from scratch.
  • You ask to "add a database to Nullstone", "wire up the cluster", "set an env var for the app", "add a capability", "override for preview/staging", "add a Slack notification on deploy".
  • You mention a Nullstone block type (app, datastore, cluster, cluster namespace, network, domain, subdomain, ingress) in the context of config files.

It does not trigger for module authoring (Terraform source code), Nullstone CLI invocations, or UI-only configuration.

What it does

When you ask Claude to add or modify a block, the skill:

  1. Resolves the module via the MCP — modules_find to discover candidates, modules_describe to get the module's category and expected vars/connections/capabilities.
  2. Places the block under the correct top-level key based on the module category:
    • appapps
    • datastoredatastores
    • networknetworks
    • domaindomains
    • subdomainsubdomains
    • ingressingresses
    • clusterclusters
    • cluster-namespacecluster_namespaces
    • other/generic → blocks
  3. Emits the block following the style rules below.
  4. Sanity-checks against the bundled JSON schema.

If the MCP is unavailable, the skill asks you to confirm the module and category rather than guessing — placing a block under the wrong top-level key silently breaks Nullstone.

Style rules it enforces

Field order inside a block

module
module_version
connections
vars
environment       # apps only
capabilities      # apps only

Top-level key order in the document

events
domains
subdomains
ingresses
apps
datastores
cluster_namespaces
clusters
networks
blocks

events sits on top because it's orthogonal; the rest is a dependency order (consumers above providers) so a reader sees the "what" before the "how".

module_version

Omitted unless you explicitly ask Claude to pin a version.

Capabilities

Map form by default:

yaml
capabilities:
  postgres:
    module: nullstone/aws-postgres-access
    connections:
      postgres: db

Array form (- name: postgres, …) is only used when you explicitly request it, or when namespace-based disambiguation is needed for colliding capabilities on the same app.

Connection targets

Shortest string form. Segments matching the file's own scope are omitted.

SituationForm
Same stack, same envblock-name
Same stack, different envenv-name.block-name
Different stack, different envstack-name.env-name.block-name
Shared infra in global stack/global envglobal.global.block-name

The object form ({ block_name, env_name, stack_name }) is only used on explicit request.

Overlay rules

In <env>.yml / previews.yml:

  • Include only fields that differ from the base.
  • Omit module unless you're changing it.
  • environment entries are additive — overlays append, they don't replace.

Canonical examples

Global single-stack baseline

yaml
# Path: .nullstone/config.yml
version: "0.1"

subdomains:
  api-subdomain:
    module: nullstone/aws-subdomain
    connections:
      domain: global.global.acme-domain

apps:
  api:
    module: nullstone/aws-fargate-service
    connections:
      cluster-namespace: namespace0
      subdomain: api-subdomain
    vars:
      num_tasks: 1
      cpu: 256
      memory: 512
    environment:
      LOG_LEVEL: info
      BASE_URL: "{{ NULLSTONE_ENV }}.acme.com"
    capabilities:
      postgres:
        module: nullstone/aws-postgres-access
        connections:
          postgres: db

datastores:
  db:
    module: nullstone/aws-rds-postgres
    connections:
      network: network0
    vars:
      postgres_version: "16"
      instance_class: "db.t3.medium"
      allocated_storage: 50

cluster_namespaces:
  namespace0:
    module: nullstone/aws-fargate-namespace
    connections:
      cluster: fargate0

clusters:
  fargate0:
    module: nullstone/aws-fargate
    connections:
      network: network0

networks:
  network0:
    module: nullstone/aws-network
    vars:
      cidr: "10.0.0.0/16"
      private_subnets:
        - "10.0.1.0/24"
        - "10.0.2.0/24"
      public_subnets:
        - "10.0.101.0/24"
        - "10.0.102.0/24"

Preview overlay (diffs only)

yaml
# Path: .nullstone/previews.yml
version: "0.1"

apps:
  api:
    environment:
      LOG_LEVEL: debug

datastores:
  db:
    vars:
      instance_class: "db.t3.small"
      allocated_storage: 20

Stack-scoped with cross-stack connection

yaml
# Path: .nullstone/stacks/web/config.yml
version: "0.1"

subdomains:
  api-subdomain:
    module: nullstone/aws-subdomain
    connections:
      domain: global.global.acme-domain

apps:
  api:
    module: nullstone/aws-fargate-service
    connections:
      cluster-namespace: namespace0
      subdomain: api-subdomain
    vars:
      num_tasks: 2
      cpu: 512
      memory: 1024

cluster_namespaces:
  namespace0:
    module: nullstone/aws-fargate-namespace
    connections:
      cluster: fargate0

clusters:
  fargate0:
    module: nullstone/aws-fargate
    connections:
      network: network0

Overriding the skill

Claude will deviate from the style rules when you explicitly ask — e.g. "use the array form for capabilities here", "pin module_version", "use the full object form for this connection so future readers see the env explicitly". The skill treats your instructions as authoritative.

When it might miss

  • If the MCP isn't installed or modules_find/modules_describe returns nothing, the skill falls back to asking you. Don't guess a top-level key from the module name alone — always confirm the category.
  • If you're editing an existing file that already uses a different style (e.g. array-form capabilities), Claude will match the existing style unless you tell it to reformat.

Bundled reference material

The skill ships with:

See also