Skip to content

Schema Versions

This page is the canonical schema-version history for jackin-owned configuration files and role manifests. It is written for operators, role authors, migration authors, and agents that need to understand which fields exist in which schema version.

Breaking changes to schemas are expected — that is how the project explores ideas without dragging compatibility shims forward. The trade-off is that operators and role authors should never have to hand-edit a TOML file to recover from an upgrade. Versioning resolves the tension:

  • Each schema file carries its own version stamp. When jackin reads the file, it compares the on-disk version against the binary’s CURRENT_*_VERSION and applies any pending migration steps before parsing, so operators see a working setup after every upgrade.
  • Operator-owned files migrate automatically. config.toml and ~/.config/jackin/workspaces/<name>.toml are rewritten in place on startup; the operator does nothing.
  • Role-owned files migrate explicitly. Role authors run jackin role migrate <role-repo-path> on their desktop to rewrite a jackin.role.toml against the latest schema, then commit and push the result. Jackin never writes back into a role repo on its own — that would silently mutate someone else’s source tree. CI, validation workflows, and Renovate-style migration automation use the standalone jackin-validate --migrate <role-repo-path> binary so role repos do not need the full Jackin operator CLI.
  • Migrations are a hard PR-review rule. Every change to one of the three versioned files must bump the corresponding CURRENT_*_VERSION, add a migration step, and update this page. Adding a new enum variant counts as a schema-breaking change: old binaries cannot parse manifests that use the new variant. The full rule lives in AGENTS.md and PULL_REQUESTS.md.
  • Version mismatches produce actionable errors. The version check runs before full TOML deserialization, so old binaries always surface a clear message rather than a cryptic parse error. When a manifest’s version is newer than what the binary knows about, jackin rejects it with: role manifest is at {version}, this binary only understands up to {CURRENT_MANIFEST_VERSION}; upgrade jackin. Current binaries accept older role manifests when the file only uses fields and enum values that existed at that older version. If an older-stamped manifest uses a newer feature, jackin rejects it with a feature-specific jackin role migrate <role-repo-path> hint.

The split-workspace layout described in Configuration File makes per-file migration tractable: legacy global files and per-workspace files migrate independently, so a dotfile repo that is partially old still upgrades cleanly.

FileCurrent versionOwnerMigration mode
~/.config/jackin/config.tomlv1alpha2jackinAutomatic on startup
~/.config/jackin/workspaces/<name>.tomlv1alpha2jackinAutomatic on startup
jackin.role.tomlv1alpha3Role repositoryDesktop: jackin role migrate <role-repo-path>; CI/automation: jackin-validate --migrate <role-repo-path>

Each entry is one upgrade path the current binary applies. tests/migration_fixtures.rs walks every fixture on every CI run, so a regression breaks here before it breaks on a delayed operator’s machine. Newest first; append, never edit.

File kindPredecessorMigration modeFixture
Manifest (jackin.role.toml)v1alpha2Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-validate --migrate <role-repo-path>tests/fixtures/migrations/manifest/from-v1alpha2/meta.toml

Summary: formalizes OpenCode agent support. The opencode enum variant in agents and the [opencode] config table require v1alpha3; older-stamped manifests still load as long as they do not use OpenCode. The migration is a no-op restamp: no field renames, no data moved.

Before (v1alpha2 manifest with OpenCode):

version = "v1alpha2"
dockerfile = "Dockerfile"
agents = ["claude", "opencode"]
[claude]
plugins = []
[opencode]
model = "zai-coding-plan/glm-5.1"

After (v1alpha3):

version = "v1alpha3"
dockerfile = "Dockerfile"
agents = ["claude", "opencode"]
[claude]
plugins = []
[opencode]
model = "zai-coding-plan/glm-5.1"
File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha1Automatic on startuptests/fixtures/migrations/config/from-v1alpha1/meta.toml
Workspace (workspaces/<name>.toml)v1alpha1Automatic on startuptests/fixtures/migrations/workspace/from-v1alpha1/meta.toml
Manifest (jackin.role.toml)v1alpha1Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-validate --migrate <role-repo-path>tests/fixtures/migrations/manifest/from-v1alpha1/meta.toml

Summary: restamps existing v1alpha1 files as v1alpha2 and moves version = "v1alpha2" to the first line. This is intentionally a sequential migration rather than a silent rewrite of v1alpha1: operators already have v1alpha1 files where the version key may sit below other top-level keys.

Before (v1alpha1 workspace file — excerpt):

workdir = "/workspace/prod"
allowed_roles = ["the-architect"]
last_role = "the-architect"
version = "v1alpha1"

After (v1alpha2):

version = "v1alpha2"
workdir = "/workspace/prod"
allowed_roles = ["the-architect"]
last_role = "the-architect"
File kindPredecessorMigration modeFixture
Config (config.toml)legacyAutomatic on startuptests/fixtures/migrations/config/from-legacy/meta.toml
Workspace (workspaces/<name>.toml)legacyAutomatic on startuptests/fixtures/migrations/workspace/from-legacy/meta.toml
Manifest (jackin.role.toml)legacyDesktop: jackin role migrate <role-repo-path>; CI/automation: jackin-validate --migrate <role-repo-path>tests/fixtures/migrations/manifest/from-legacy/meta.toml

Summary: introduces the top-level version field. The migration adds version = "v1alpha1" to every file kind and leaves all existing keys, comments, and section ordering untouched. Splitting legacy [workspaces.<name>] tables out of config.toml runs as a separate startup step (see Configuration File); the version migration above is independent of that split.

Before (legacy operator config — excerpt):

[roles.agent-smith]
git = "https://github.com/jackin-project/jackin-agent-smith.git"
trusted = true

After (v1alpha1):

version = "v1alpha1"
[roles.agent-smith]
git = "https://github.com/jackin-project/jackin-agent-smith.git"
trusted = true

Schema versions use Kubernetes-style names:

FormMeaning
v1alpha1Unstable schema for the future stable v1 family
v1alpha2Next unstable schema in the same family
v1beta1More mature but still not stable
v1Stable schema

The current project is still unstable, so all current schemas use the v1alpha* family.

legacy means the file has no top-level version field. For operator config, jackin migrates this automatically before parsing.

Change to v1alpha1Detail
Addedversion = "v1alpha1"
PreservedGlobal agent auth, GitHub auth, env, role sources, Docker mounts
RemovedNone
RenamedNone

The split-from-config.toml work for legacy [workspaces.<name>] tables runs as a separate startup migration alongside the version stamp; see Configuration File.

FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha2
[claude].auth_forwardstringNolegacysync, api_key, oauth_token, or ignore
[codex].auth_forwardstringNolegacysync, api_key, or ignore
[amp].auth_forwardstringNolegacysync, api_key, or ignore
[opencode].auth_forwardstringNolegacysync, api_key, or ignore
[github].auth_forwardstringNolegacysync, token, or ignore
[github.env]tableNolegacyOperator env values for GitHub token auth
[env]tableNolegacyGlobal operator env layer
[roles.<role>]tableNolegacyRole source config
[roles.<role>].gitstringYes when role is declaredlegacyRole repository URL
[roles.<role>].trustedboolNolegacyTrust-on-first-use state
[roles.<role>.env]tableNolegacyPer-role operator env layer
[docker.mounts]tableNolegacyGlobal and scoped Docker mount config
[workspaces]tableNolegacyLegacy read-only compatibility location; migrated into workspace files

Full operator configuration examples live in Configuration File.

Workspace files live at ~/.config/jackin/workspaces/<name>.toml.

legacy means either a standalone workspace file with no version, or a [workspaces.<name>] table embedded in legacy config.toml.

Change to v1alpha1Detail
Addedversion = "v1alpha1"
PreservedWorkdir, mounts, role selection, env, auth overrides, keep-awake, 1Password account
RemovedNone
RenamedNone

Legacy embedded [workspaces.<name>] tables in config.toml are split into per-workspace files by a separate startup migration; see Configuration File.

FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha2
workdirstringYeslegacyContainer working directory
allowed_rolesstring arrayNolegacyRoles allowed in this workspace
default_rolestringNolegacyPreferred role for new sessions
default_agentstringNolegacyclaude, codex, amp, or opencode; omitted defaults to Claude
last_rolestringNolegacyLast role selected by the operator
op_accountstringNolegacy1Password account selector
git_pull_on_entryboolNolegacyPull mounted repositories on entry
[env]tableNolegacyWorkspace operator env layer
[[mounts]]array of tablesNolegacyWorkspace mounts
[[mounts]].srcstringYeslegacyHost path
[[mounts]].dststringYeslegacyContainer path
[[mounts]].readonlyboolNolegacyDefaults to false
[[mounts]].isolationstringNolegacyshared, worktree, or clone; legacy default is shared
[keep_awake].enabledboolNolegacymacOS keep-awake toggle
[claude].auth_forwardstringNolegacyWorkspace Claude auth override
[codex].auth_forwardstringNolegacyWorkspace Codex auth override
[amp].auth_forwardstringNolegacyWorkspace Amp auth override
[opencode].auth_forwardstringNolegacyWorkspace OpenCode auth override
[github].auth_forwardstringNolegacyWorkspace GitHub auth override
[github.env]tableNolegacyWorkspace GitHub token env values
[roles.<role>.env]tableNolegacyPer-workspace, per-role env override
[roles.<role>.claude].auth_forwardstringNolegacyPer-workspace, per-role Claude auth override
[roles.<role>.codex].auth_forwardstringNolegacyPer-workspace, per-role Codex auth override
[roles.<role>.amp].auth_forwardstringNolegacyPer-workspace, per-role Amp auth override
[roles.<role>.opencode].auth_forwardstringNolegacyPer-workspace, per-role OpenCode auth override
[roles.<role>.github].auth_forwardstringNolegacyPer-workspace, per-role GitHub auth override
[roles.<role>.github.env]tableNolegacyPer-workspace, per-role GitHub token env values

legacy means the manifest has no top-level version field. Jackin does not auto-write role repositories during normal role loading. Run jackin role migrate <role-repo-path> to rewrite a local copy on a desktop, or jackin-validate --migrate <role-repo-path> in CI and automated migration jobs.

Change to v1alpha1Detail
Addedversion = "v1alpha1"
MovedNone
PreservedDockerfile, published image, identity, agents, runtime settings, hooks, env prompts
RemovedNone
RenamedNone
FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha3
dockerfilestringYeslegacyRelative path to role Dockerfile
published_imagestringNolegacyPre-built role image override
agentsstring arrayNolegacyclaude, codex, or amp; opencode added in v1alpha3; omitted means Claude-only
[identity].namestringNolegacyDisplay name
[claude].modelstringNolegacyClaude model override
[claude].pluginsstring arrayNolegacyClaude plugin identifiers
[[claude.marketplaces]]array of tablesNolegacyClaude plugin marketplace registrations
[[claude.marketplaces]].sourcestringYeslegacyMarketplace source
[[claude.marketplaces]].sparsestring arrayNolegacySparse checkout paths
[codex].modelstringNolegacyCodex model override
[amp]tableNolegacyEmpty marker table for Amp support
[opencode].modelstringNov1alpha3OpenCode model override in provider/model format (e.g. zai-coding-plan/glm-5.1)
[hooks].setup_oncestringNolegacyRelative path to a one-time install script that runs on first launch only
[hooks].sourcestringNolegacyRelative path to a script dot-sourced into the entrypoint shell so export and PATH mutations reach the launched agent
[hooks].preflightstringNolegacyRelative path to a per-start preflight script
[env.<NAME>]tableNolegacyInteractive env prompt declaration
[env.<NAME>].defaultstringNolegacyDefault env value
[env.<NAME>].interactiveboolNolegacyPrompt operator before launch
[env.<NAME>].skippableboolNolegacyAllow empty response
[env.<NAME>].promptstringNolegacyPrompt text
[env.<NAME>].optionsstring arrayNolegacyFixed choices
[env.<NAME>].depends_onstring arrayNolegacyDependency references such as env.PROJECT

Full role manifest examples live in Role Manifest.

Jackin does not keep every migration forever. If a file is too old and the current binary no longer includes the full path to the current schema, jackin errors and tells the operator to upgrade through an older jackin first.

Migration entry points:

File kindCode entry point
Configsrc/config/migrations.rs
Workspacesrc/config/migrations.rs
Role manifestsrc/manifest/migrations.rs