config.json
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
| Key | Type | Notes |
|---|---|---|
version | string | Current format version. Use "2.0". |
remote | string | Host alias from ~/.divekit/hosts.json. |
groupId | integer | Work target group ID. |
name | string | Optional repository name template. When omitted, Divekit uses {{distribution}}-{{uuid}}. |
members | object | Member source and default permissions. |
members.path | string | Path to the members.json file. Supports $DIVEKIT_MEMBERS/... and relative paths resolved through the members base directory. |
members.permissions | string | GitLab access level assigned to configured members, for example guest, reporter, developer, maintainer, or owner. |
evaluationPipeline | object | Enables separated eval target handling. |
evaluationPipeline.enabled | boolean | Enables the generated eval target and cross-repository setup. |
evaluationPipeline.groupId | integer | Optional group ID for eval repositories. |
groupLayout | object | Controls how student and eval groups are derived. |
groupLayout.mode | string | Group-resolution strategy: distribution-subgroups (default) or legacy. |
groupLayout.rootGroupId | integer | Optional root group ID used to derive distribution subgroups. Defaults to the work target’s groupId. |
snapshot | object | Optional research snapshot target configuration. |
snapshot.remote | string | Host alias from ~/.divekit/hosts.json used for snapshot writes. Defaults to the work target remote. |
snapshot.groupId | integer | Snapshot root group used by divekit snapshot. Interactive runs can store this after you choose a root group. |
deleteExistingRepositories | boolean | Destructive reset option before distribution. |
scripting | object | Language and file-extension mapping used by scripting and token tooling. |
scripting.languages | array of strings | Enabled language packs. If omitted in auto mode, Divekit can discover languages. |
scripting.extensions | object | Maps file patterns such as *.java to language packs. |
scripting.files | object | File-specific mapping alias that is merged with scripting.extensions. |
scripting.mode | string | Scripting mode. auto enables language discovery; object form may also use manual mappings. |
variables | object | Global token delimiter and fixed values. |
variables.variableDelimiter | string | Opening delimiter for tokens. |
variables.variableDelimiterEnd | string | Optional closing delimiter when start and end should differ. |
variables.values | object | Fixed 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.
| Mode | Resulting layout |
|---|---|
distribution-subgroups (default) | Repositories live below a per-distribution subgroup of the root group. |
legacy | Work 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.
deleteExistingRepositoriesand--dangerously-delete-group-projectsonly cover the configured target groups. Divekit warns about legacy repositories left in the root group but does not delete them.--freshignores 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.pathpoints to amembers.jsonfile. See members.json.namecontrols 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, distributionST2M4creates names such asST2M4-b8520e99-.... Setnameonly 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 nameuses the samenamerule to reconcile already distributed GitLab project names and URL paths.evaluationPipelineis the canonical stored key. OldersecurePipelineconfigs are still accepted on read.- When the evaluation pipeline is enabled, Divekit creates the
evaltarget internally. It is not configured as a second top-level target in the stored file. - The implicit
evaltarget inherits the repository name rule from the work target. Divekit does not add an automatic-evalsuffix to repository names. linkingis inferred at runtime when the evaluation pipeline is enabled. It is an implementation detail and is normally not written back toconfig.json.snapshotis optional. When omitted,divekit snapshotuses the work remote and derives the snapshot group fromgroupLayout.rootGroupIdorgroupId.snapshot.groupIdis the only root group value prefilled in the interactive snapshot prompt; the workgroupIdis shown as a fallback placeholder.divekit initcreates this file for a distribution. It does not requirevariation.jsonorindividualization.json.
Related pages: