Skip to content

Working with Generators

A generator is an identity principal — a CI/CD pipeline, automation tool, service, or team — that creates and manages Brokkr resources. Each generator receives a Prefixed API Key (PAK) scoped to itself: it can create stacks, templates, and deployment objects, but can only access resources it created. Unlike the admin PAK, a generator PAK cannot perform administrative operations such as creating other generators or managing agents.

The generator is also Brokkr’s tenant. Creating a generator and handing over its PAK is how you onboard a team or an application onto a shared broker: its stacks are its own, its templates are private to it, and an agent only receives its stacks after registering with it. Generators are what the operator console’s tenant scope selector lists, and what ?pak_id= narrows admin listings to. If you are standing up a multi-team install, start from Multi-Tenant Setup, which uses the steps below as its onboarding path; for the tenancy rules themselves see Multi-Tenancy.

This guide covers creating generators, integrating them with CI/CD systems, registering agents, and managing their lifecycle.

  • Admin PAK for creating and managing generators
  • Access to the Brokkr broker API
  • CI/CD system or automation tool to configure

Create a new generator using the admin PAK:

Terminal window
curl -X POST "http://broker:3000/api/v1/generators" \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{
"name": "github-actions-prod",
"description": "Production deployment pipeline"
}'

The response includes the generator details and its PAK:

{
"generator": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2026-10-06T01:59:35.569566Z",
"updated_at": "2026-10-06T01:59:35.574293Z",
"deleted_at": null,
"name": "github-actions-prod",
"description": "Production deployment pipeline",
"last_active_at": null,
"is_active": true,
"is_system": false
},
"pak": "brokkr_BRgen12ab_GeneratorLongTokenExample01"
}

The PAK is only returned once at creation time, and the generator’s UUID is what stack creation requests must reference as generator_id. Store both immediately in your secret management system — never in source code, configuration files, or logs:

  • GitHub Actions: Add as a repository or organization secret
  • GitLab CI: Add as a protected variable
  • Jenkins: Store in credentials manager
  • Vault/AWS Secrets Manager: Store with appropriate access policies

If you lose the PAK, you’ll need to rotate it (see PAK Rotation below).

If you have the PAK but not the ID, read it back from the credential itself — the generator field is the tenant ID:

Terminal window
curl -s -X POST "http://broker:3000/api/v1/auth/pak" \
-H "Authorization: Bearer $GENERATOR_PAK" | jq -r '.generator'

A new generator is immediately a tenant. Confirm it shows up in the tenant list that backs the operator console’s scope selector (admin credential required):

Terminal window
curl -s "http://broker:3000/api/v1/paks" \
-H "Authorization: Bearer $ADMIN_PAK"
[
{ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "github-actions-prod" }
]

The path is /api/v1/paks, not /api/v1/auth/paks. Operators can then narrow the admin fleet, stack, and agent-event listings to this generator with ?pak_id=<generator-id>. That parameter is a display filter for an admin who could already see everything — it is not an access boundary, so never substitute it for handing a team its own generator PAK.

When a generator creates a stack, the request body must include generator_id set to the generator’s own ID — the broker rejects any other value for a generator PAK.

One pattern, in one place: CI/CD with Generators, Step 7 shows a complete workflow that pushes the rendered manifest as YAML to an existing stack with the generator PAK. With the brokkr CLI the step is one idempotent command, brokkr apply -f ./manifests --stack <name>; see Submitting a Folder of Manifests. The same two forms work in GitLab CI or any other runner.

Do not create a stack per commit. The stack is the application and lives on; each push is a new deployment object in it, and the agent applies the newest.

Generators can create stack templates and instantiate them into stacks they own. A template carries template_content (Tera-templated YAML) and parameters_schema (a JSON Schema string); instantiation renders the template into a deployment object within an existing stack:

Terminal window
# Create a template (using generator PAK)
curl -X POST "http://broker:3000/api/v1/templates" \
-H "Authorization: Bearer $GENERATOR_PAK" \
-H "Content-Type: application/json" \
-d '{
"name": "web-service",
"description": "Standard web service deployment",
"template_content": "...",
"parameters_schema": "..."
}'
# Instantiate the template into an existing stack
curl -X POST "http://broker:3000/api/v1/stacks/$STACK_ID/deployment-objects/from-template" \
-H "Authorization: Bearer $GENERATOR_PAK" \
-H "Content-Type: application/json" \
-d '{
"template_id": "'"$TEMPLATE_ID"'",
"parameters": {
"replicas": 3,
"image": "myapp:v1.2.3"
}
}'

The instantiation endpoint returns 201 Created with the rendered deployment object. See Stack Templates for the full workflow.

A generator can read and instantiate its own templates plus admin-owned system templates; another generator’s template returns 403 template_not_accessible. Publish anything meant to be shared across teams as a system template using the admin PAK.

View all generators (admin only):

Terminal window
curl "http://broker:3000/api/v1/generators" \
-H "Authorization: Bearer $ADMIN_PAK"

A generator can view its own details:

Terminal window
curl "http://broker:3000/api/v1/generators/$GENERATOR_ID" \
-H "Authorization: Bearer $GENERATOR_PAK"

The update endpoint takes the complete generator object (PUT replaces, it does not patch), so fetch the current record, modify the fields you want, and send the whole object back:

Terminal window
curl -s "http://broker:3000/api/v1/generators/$GENERATOR_ID" \
-H "Authorization: Bearer $GENERATOR_PAK" \
| jq '.description = "Updated description"' \
| curl -X PUT "http://broker:3000/api/v1/generators/$GENERATOR_ID" \
-H "Authorization: Bearer $GENERATOR_PAK" \
-H "Content-Type: application/json" \
-d @-

Soft-delete a generator (admin or generator itself):

Terminal window
curl -X DELETE "http://broker:3000/api/v1/generators/$GENERATOR_ID" \
-H "Authorization: Bearer $ADMIN_PAK"

Deleting a generator cascades the soft-delete to all stacks owned by the generator and their deployment objects. This is handled by a database trigger, so the cascade is atomic.

An agent must be registered with a generator before any of that generator’s stacks reach it. Registration is the agent’s opt-in consent boundary, and it applies to every way a stack can be associated with an agent:

  • Creating an explicit target for an unregistered agent returns 403 agent_not_registered, and admin cannot bypass it.
  • A shared label or annotation only associates a stack with an agent that is registered with the stack’s owning generator. An agent with no registrations receives nothing from label or annotation matching, and two generators can safely reuse the same label vocabulary without crossing into each other.

Registration is performed by an admin or by the agent itself — a generator PAK cannot register agents on its own behalf. This section covers registration from the admin’s side; for the full operational workflow (including agent self-registration at startup) see Agent Registration.

Register an agent with the generator (admin, or the agent acting on itself — a generator PAK is rejected):

Terminal window
curl -X POST "http://broker:3000/api/v1/generators/$GENERATOR_ID/register" \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "f1e2d3c4-b5a6-7890-abcd-ef0123456789"
}'

The response is the registration record:

{
"id": "9a8b7c6d-5e4f-3210-fedc-ba9876543210",
"agent_id": "f1e2d3c4-b5a6-7890-abcd-ef0123456789",
"generator_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"registered_at": "2025-01-02T10:05:00Z"
}

Re-registering an already-registered agent returns 409 with code already_registered (the call is not idempotent). When an agent self-registers, it omits agent_id and authenticates with its own credentials.

View the agents registered with a generator:

Terminal window
curl "http://broker:3000/api/v1/generators/$GENERATOR_ID/registered-agents" \
-H "Authorization: Bearer $ADMIN_PAK"

Remove an agent’s registration. This is destructive: it cascades by removing the agent’s explicit targets for this generator’s stacks and pushes a target-changed notification to the agent, which prunes those Kubernetes resources on its next reconcile.

Terminal window
curl -X DELETE "http://broker:3000/api/v1/generators/$GENERATOR_ID/register" \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "f1e2d3c4-b5a6-7890-abcd-ef0123456789"
}'

The brokkr CLI wraps these endpoints (an admin PAK is required for cross-entity operations):

Terminal window
# Register an agent with a generator. Safe to run again: a repeat prints
# a line that starts with "unchanged:" and exits 0.
brokkr register --agent <agent-id> --generator <generator-id>
# Deregister (destructive — cascades target removal)
brokkr deregister --agent <agent-id> --generator <generator-id>
# List registrations by agent or by generator
brokkr registrations --generator <generator-id>

Rotate the generator’s PAK for security best practices or if the current PAK is compromised:

Terminal window
curl -X POST "http://broker:3000/api/v1/generators/$GENERATOR_ID/rotate-pak" \
-H "Authorization: Bearer $GENERATOR_PAK"

The response contains the new PAK:

{
"generator": {
"id": "a1b2c3d4-...",
"name": "github-actions-prod",
...
},
"pak": "brokkr_BRnew34cd_GeneratorLongTokenExample02"
}

After rotation:

  1. The old PAK is immediately invalidated — the API endpoint replaces the stored hash and evicts the old PAK from the broker’s auth cache, so it stops working right away. (This immediate invalidation applies only to API rotation; the CLI rotate generator command behaves differently — see Managing PAKs.)
  2. Update all CI/CD systems with the new PAK
  3. Verify deployments work with the new credentials

Consider rotating PAKs:

  • On a regular schedule (quarterly, annually)
  • When team members with access leave
  • If the PAK may have been exposed
  • After security incidents

Generators operate under a scoped permission model: a generator PAK can manage the generator itself and the resources it created, while administrative operations remain admin-only. See the permission model and resource scoping sections of the Generators API Reference for the full matrix.

Create a separate generator for each deployment pipeline or team. Because the generator is the tenant, this is what gives you clear resource ownership, independent PAK rotation, per-team separation, scoped operator views, and easier auditing. Sharing one generator across two teams merges them into one tenant.

Use descriptive names that identify purpose and scope, e.g. github-actions-prod, gitlab-ci-staging, or team-platform-prod.

If API calls fail with 401 or 403:

  1. Verify the PAK is correct — PAKs do not expire, so a previously working key has been rotated or revoked
  2. Check whether the PAK was rotated elsewhere, or the generator deleted (deleting a generator revokes its PAK)
  3. Ensure you’re using the generator PAK, not the admin PAK (for generator-scoped operations)

If a generator cannot see expected stacks or templates:

  1. Verify the resources were created with this generator’s PAK
  2. Resources created by other generators are not visible; another generator’s template returns 403 template_not_accessible
  3. Use admin PAK to view all resources across generators

If an agent applies nothing despite matching labels, check its registrations first — a label match is only honored for generators the agent has registered with:

Terminal window
curl -s "http://broker:3000/api/v1/agents/$AGENT_ID/registrations" \
-H "Authorization: Bearer $ADMIN_PAK"

An agent with no registrations, or one missing this generator, receives nothing from label or annotation matching. Register it (above) or set broker.generatorIds on the agent deployment.

If you’ve lost a generator’s PAK:

  1. Use the admin PAK to rotate: POST /api/v1/generators/{id}/rotate-pak
  2. Store the new PAK securely
  3. Update all systems using the old PAK