config.json

Reference for the primary distribution configuration file.

config.json is the primary distribution configuration file used by divekit distribute, fetch, patch, overview, and related commands.

Default location:

.divekit/distributions/<distribution>/config.json

Current Stored Format

The current persisted format is a flat version: "2.0" document. Internally, Divekit still expands this into named targets such as work and eval.

{
  "version": "2.0",
  "remote": "gitnrw",
  "groupId": 12345,
  "members": {
    "path": "$DIVEKIT_MEMBERS/st2_members.json",
    "permissions": "developer"
  },
  "evaluationPipeline": {
    "enabled": true,
    "groupId": 67890
  },
  "snapshot": {
    "remote": "research",
    "groupId": 24680
  }
}

Keys

KeyTypeNotes
versionstringCurrent format version. Use "2.0".
remotestringHost alias from ~/.divekit/hosts.json.
groupIdintegerWork target group ID.
namestringOptional repository name template. When omitted, Divekit uses {{distribution}}-{{uuid}}.
membersobjectMember source and default permissions.
members.pathstringPath to the members.json file. Supports $DIVEKIT_MEMBERS/... and relative paths resolved through the members base directory.
members.permissionsstringGitLab access level assigned to configured members, for example guest, reporter, developer, maintainer, or owner.
evaluationPipelineobjectEnables separated eval target handling.
evaluationPipeline.enabledbooleanEnables the generated eval target and cross-repository setup.
evaluationPipeline.groupIdintegerOptional group ID for eval repositories.
groupLayoutobjectControls how student and eval groups are derived.
groupLayout.modestringGroup-resolution strategy: distribution-subgroups (default) or legacy.
groupLayout.rootGroupIdintegerOptional root group ID used to derive distribution subgroups. Defaults to the work target’s groupId.
snapshotobjectOptional research snapshot target configuration.
snapshot.remotestringHost alias from ~/.divekit/hosts.json used for snapshot writes. Defaults to the work target remote.
snapshot.groupIdintegerSnapshot root group used by divekit snapshot. Interactive runs can store this after you choose a root group.
deleteExistingRepositoriesbooleanDestructive reset option before distribution.
scriptingobjectLanguage and file-extension mapping used by scripting and token tooling.
scripting.languagesarray of stringsEnabled language packs. If omitted in auto mode, Divekit can discover languages.
scripting.extensionsobjectMaps file patterns such as *.java to language packs.
scripting.filesobjectFile-specific mapping alias that is merged with scripting.extensions.
scripting.modestringScripting mode. auto enables language discovery; object form may also use manual mappings.
variablesobjectGlobal token delimiter and fixed values.
variables.variableDelimiterstringOpening delimiter for tokens.
variables.variableDelimiterEndstringOptional closing delimiter when start and end should differ.
variables.valuesobjectFixed token values available during distribution.

Repository Name Templates

The optional top-level name value is rendered once for each repository group. When omitted, Divekit uses {{distribution}}-{{uuid}}.

For example, use the first configured member’s GitLab username:

{
  "name": "exercise-{{username}}"
}

See Repository Name Templates for the complete data-field and function reference, Go template syntax, stable numbering, examples, and error behavior.

Group Layout

groupLayout.mode controls where Divekit creates repositories. If the key is missing, distribution-subgroups applies.

ModeResulting layout
distribution-subgroups (default)Repositories live below a per-distribution subgroup of the root group.
legacyWork repositories stay directly in the configured groupId; eval repositories use evaluationPipeline.groupId or an eval subgroup below the work group.

groupLayout.rootGroupId identifies the group below which Divekit creates the per-distribution subgroup. If it is omitted, Divekit uses the work target’s groupId and stores the resolved root for the run.

Without an explicit evaluationPipeline.groupId, the default layout depends on whether the evaluation pipeline is enabled:

evaluationPipeline.enabled = true
  <root>/<distribution>/work/<repository>
  <root>/<distribution>/eval/<repository>

evaluationPipeline.enabled = false (or key omitted)
  <root>/<distribution>/<repository>

Without an evaluation pipeline, Divekit deliberately omits the intermediate work subgroup because there is no sibling eval subgroup.

With the pipeline enabled and an explicit evaluationPipeline.groupId, work repositories use <root>/<distribution>/<repository> and eval repositories use <evaluationPipeline.groupId>/<distribution>/<repository>. Divekit creates no intermediate work or eval subgroups in this case.

Required Permissions

distribution-subgroups checks for the required subgroups on every run and creates any that are missing. The GitLab token needs subgroup creation permission in each parent group where a subgroup must be created, including a separate eval root when configured.

Set "groupLayout": {"mode": "legacy"} if repositories should remain directly in groupId. With an evaluation pipeline, also set evaluationPipeline.groupId to an existing group if the token cannot create subgroups; otherwise legacy still creates an eval subgroup when it is missing.

Migrating an Existing Distribution

Changing an existing flat distribution to distribution-subgroups does not move its repositories automatically:

  • Without an evaluation pipeline, existing repositories directly below the root group are reused, so reruns do not create duplicates.
  • Repositories added later are created in the new distribution subgroup. The distribution can therefore be split across both locations during migration.
  • deleteExistingRepositories and --dangerously-delete-group-projects only cover the configured target groups. Divekit warns about legacy repositories left in the root group but does not delete them.
  • --fresh ignores persisted remotes and creates repositories in the new subgroup. Old root-group repositories and their member access remain intact.

Moving existing repositories requires a separate migration in GitLab. Set groupLayout.rootGroupId explicitly to keep the intended root unambiguous.

Notes

  • members.path points to a members.json file. See members.json.
  • name controls the generated repository names. The default does not need to be stored: {{distribution}} is replaced with the distribution folder name and {{uuid}} with the group UUID. For example, distribution ST2M4 creates names such as ST2M4-b8520e99-.... Set name only when you need a custom naming pattern.
  • Repository name templates can use group context from members.json, including usernames, labels, metadata, and stable repository indexes.
  • divekit patch name uses the same name rule to reconcile already distributed GitLab project names and URL paths.
  • evaluationPipeline is the canonical stored key. Older securePipeline configs are still accepted on read.
  • When the evaluation pipeline is enabled, Divekit creates the eval target internally. It is not configured as a second top-level target in the stored file.
  • The implicit eval target inherits the repository name rule from the work target. Divekit does not add an automatic -eval suffix to repository names.
  • linking is inferred at runtime when the evaluation pipeline is enabled. It is an implementation detail and is normally not written back to config.json.
  • snapshot is optional. When omitted, divekit snapshot uses the work remote and derives the snapshot group from groupLayout.rootGroupId or groupId. snapshot.groupId is the only root group value prefilled in the interactive snapshot prompt; the work groupId is shown as a fallback placeholder.
  • divekit init creates this file for a distribution. It does not require variation.json or individualization.json.

Related pages: