Configuration Sync to Git
The Workspace can mirror its administrative configuration — schemas, roles, permissions, connectors, scheduled tasks and other definitions — into a Git repository. Every change made by an admin is committed automatically, with the author and an optional message attached. When a remote is configured, the same commits are pushed upstream so the repository becomes the audit trail and the disaster-recovery copy of the workspace configuration.
Use it to:
- Track who changed which configuration setting, and when.
- Promote configuration from staging to production by pulling the same commits into another workspace.
- Recover a known-good configuration after a misconfiguration or a restore.
Scope
Only administrative configuration (the "definitions" exported by the workspace) is tracked. Graph content, ingested documents, embeddings and search indexes are not stored in this repository — those belong to backups. See Backup and restore.
How it works
On startup, when MSK_GIT_TRACK_STATE_PATH is set, the workspace opens (or
initializes) a Git repository at that path and checks out the configured
branch. From then on, every tracked administrative change triggers an export
of the current configuration into the repository's definitions/ folder,
followed by a commit with the author set to the user who made the change.
If MSK_GIT_REMOTE_URL is also set, the workspace pushes the branch upstream
after each commit using the supplied credentials.
Required environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
MSK_GIT_TRACK_STATE_PATH |
yes | — | Absolute path to the local directory used as the Git working tree. Created and git init-ed on first start if it doesn't already contain a .git folder. |
MSK_GIT_TRACK_STATE_BRANCH |
no | main |
Branch that receives the configuration commits. |
MSK_GIT_REMOTE_URL |
no | — | HTTPS URL of the remote repository to push commits to. When unset, history stays local. |
MSK_GIT_REMOTE_USERNAME |
conditional | — | Username for the remote. Required when MSK_GIT_REMOTE_URL is set and the remote requires authentication. |
MSK_GIT_REMOTE_PASSWORD |
conditional | — | Password or personal access token for the remote. Required alongside MSK_GIT_REMOTE_USERNAME. |
Persist the repository path
MSK_GIT_TRACK_STATE_PATH must point to a location that survives container
restarts. In Docker or Kubernetes, mount a volume at that path — otherwise the
repository is recreated on every start and the history is lost.
Credentials
Use a service account or a personal access token scoped to the single configuration repository — not a long-lived user credential.
- GitHub: a fine-grained PAT with
Contents: read & writeon the target repository works as the password. SetMSK_GIT_REMOTE_USERNAMEto any non-empty string (GitHub ignores it for PAT auth). - GitLab: a project access token with the
Developerrole and thewrite_repositoryscope. - Azure DevOps: a PAT with
Code: Read & Write. Use the PAT as the password.
What ends up in the repository
The first commit on a fresh repository contains only a README.md placeholder.
Subsequent commits add and update files under definitions/. The full layout
is regenerated from the live workspace on every change, so the working tree
always reflects the workspace's current configuration — there are no partial
edits.
The tree mirrors the definitions export:
| Folder | Contents |
|---|---|
definitions/code/ |
Endpoints, AI tools, AI agents, AI assistants, skills, AI prompt templates, AI providers, entity post-processing, scheduled / data-connector / migration tasks, and custom code and search indexes. |
definitions/config/ |
Node and edge schemas, node styles and renderers, other index settings, chat policies, chat-policy enforcement settings, secret declarations, installed packages, and the search, interface, file-indexing and general settings files. |
definitions/nlp/ |
Spotters, pattern spotters, pipelines, and entity-linking configuration. |
A few of those carry rules worth knowing before you read a diff:
- Chat policies get one file per policy under
config/chat-policies, written as the same definition the admin interface edits, with enum values written as names so a diff stays readable. The built-in policies are seeded from code on every boot and stay out of the repository. - Chat-policy enforcement settings — everything governing the batched sweep —
live in
config/chat-policy-enforcement.json. - Deep research maximum limits (concurrent runs, queued runs, concurrent runs
per user, iterations, duration) ride along in
config/general.json. - Secrets export their declaration only: name and description, under
config/secrets. The value is written as the literalNOT EXPORTED, so a reader of the file or of the diff can see it was withheld rather than missed. Declarations travel because code that reads a secret only compiles where the declaration exists. - Custom AI assistants carry their chat prompt, the tools, agents and skills they pin, and whether they are shared. The built-in admin assistant is seeded from code and stays out.
- The built-in consult tool is exported once a workspace has edited it; a workspace still running the shipped code re-seeds it on boot instead.
Each commit message follows the pattern:
Configuration Sync (<optional context provided by the change>)
The author is the user who triggered the change (full name and email taken
from their workspace profile). The committer is always the
Curiosity Workspace service identity.
Do not commit manually
The repository is regenerated by the workspace on every tracked change. Manual commits or edits to the working tree will be overwritten the next time an admin changes configuration. Treat the repository as read-only on the remote side and use it for review and audit only.
Importing the definitions into another workspace
Promoting a configuration means feeding the same definitions/ tree into the
target workspace as a definitions bundle. What the import does with it:
- Overwriting an existing definition is recorded. An import that replaces an endpoint, AI tool, prompt template, entity post-processing, code / data-connector / migration task, AI provider, agent or skill leaves the same change-history entry a hand edit does, attributed to whoever ran the import, so the change can be reviewed, diffed and rolled back from the History view. Creating a definition the workspace did not have is deliberately not recorded — there is nothing to diff against.
- A live secret is never overwritten. A secret the target already has is left completely untouched, values included. A secret it lacks is created with an empty value and named in the import warnings; set its value under Manage → Configure → Secrets before the code that reads it runs.
- An assistant may pin something the target lacks. If an imported AI assistant pins a tool, agent or skill that is not in the target workspace, the assistant is imported and the missing item is reported as a warning rather than failing the whole bundle. Include the pinned definitions in the same bundle to avoid it.
Two import failure modes that no longer occur: a tool or agent whose description
spans several paragraphs used to break the parse of its file and fail the entire
import, and skills could not be created or renamed through the WebDAV definitions
mount at /dav/ because the folder was missing from its layout.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Repository is recreated on every restart | MSK_GIT_TRACK_STATE_PATH points to a non-persistent location (e.g. inside the container's writable layer). |
Mount a volume at that path. |
| Commits land locally but are never pushed | MSK_GIT_REMOTE_URL is unset, or credentials are wrong. |
Set the remote URL and verify the username/password against the provider's auth requirements. |
repository path not owned by current user in the logs |
Mounted volume is owned by a different UID inside the container. | The workspace already disables LibGit2's owner validation; if you still see this, check filesystem permissions on the mount. |
| Commits appear with no author name | The user who made the change has no profile name or email set. | Update the user's profile in the workspace; future commits use the new identity. |
See also: Configuration, Security, Backup and restore.