Everything as code

Keep a complete AI setup in a repository and import it into a clean environment.

Every example in this section was built from pieces - credentials, groups, gateways, connections, services, skills. The setup below puts all of them into files a repository can hold and a clean environment can import, so recreating production in staging is a checkout and an import, not an afternoon of clicking.

The pieces

Everything is a file, but not the same kind of file:

PieceFormHow it deploys
Security, groups, gateways, LLM connectionsOne enmasse YAMLImported - on demand or on startup
ServicesPython filesHot-deployed
SkillsA SKILL.md per directory under config/repo/skillsFiles - copied or checked out in place
SecretsEnvironment variablesNever in the repository

The YAML names services and skills that arrive as files - enmasse brings the configuration, the files bring the content, and the names are the joint between them.

The YAML

The complete configuration of a support setup - an agent credential, its group, a gateway with two tools and a prompt, and the LLM connection the tools use:

security:
  - name: agent.support
    type: apikey
    username: support-agent
    password: Zato_Enmasse_Env.Support_Agent_Key

groups:
  - name: support-agents
    members:
      - agent.support

llm:
  - name: Support LLM
    model: gpt-4o-mini
    address: https://api.openai.com/v1
    secret: Zato_Enmasse_Env.Support_LLM_Key
    timeout: 15
    max_tokens: 2048

mcp_gateway:
  - name: support
    url_path: /mcp/support
    services:
      - example.support.get-ticket
      - example.support.summarize-ticket
    security_groups:
      - support-agents
    skills:
      - ticket-triage
    validate_input: true
    is_audit_log_active: true
    max_response_size: 2000

Two properties matter:

  • No secrets - the Zato_Enmasse_Env. prefix reads each secret from an environment variable where the import runs, so this file is safe in git and each environment brings its own keys.
  • Importing the gateway also creates the REST channel that makes it reachable - the YAML above is complete.

The repository

support-ai/
├── enmasse.yaml
├── services/
│   └── support.py          # the two services the gateway names
└── skills/
    └── ticket-triage/
        └── SKILL.md        # the prompt the gateway serves

Import into a clean environment

With a fresh environment and the two environment variables set, the files go in first and the configuration follows:

# Services hot-deploy by being placed in the pickup directory
cp services/support.py ~/env/qs-1/server1/pickup/incoming/services/

# Skills are files under the server's config
cp -r skills/ticket-triage ~/env/qs-1/server1/config/repo/skills/

Then the YAML imports as one unit - in the Dashboard through System > Config > Import enmasse, or, in containers, as a mount point: enmasse.yaml under /opt/hot-deploy/enmasse/ imports on startup, as the DevOps guide describes. Either way the environment now serves /mcp/support, the agent's key works, the prompt is listed and the audit log is on - nothing was configured by hand.

Running the import again is safe - it creates what does not exist and updates what does, matching by name. That makes the YAML the reviewable unit of change: raising max_response_size is a one-line diff, a pull request and a re-import.

Failure behavior

The joints are names, and names can dangle:

  • A service in the gateway's list that is not deployed yet is not an error - the gateway imports, and the tool appears the moment the service hot-deploys. The export marks such services with a Not deployed note, as sharing with clients shows.
  • A skill named in skills that has no directory yet is not served until the files arrive - prompts/list shows what is there.
  • A missing environment variable does not stop the import - the value becomes a placeholder that names the missing variable, so the first call that needs the secret fails and the placeholder in the error points straight at which variable was not set.

See also

FeatureWhat it does
GitOpsThe llm and mcp_gateway enmasse sections in full
Multi-agent isolationThe same layout grown to several agents and gateways
Self-hosted modelsPer-environment YAML that swaps the model backends