jackin'
Behind jackin' — InternalsRuntime Model

Schema Versions

Historical config, workspace, and role manifest 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.

Why versioning

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-role 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.

Current versions

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

Timeline

Each entry is one upgrade path the current binary applies. crates/jackin/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.

Manifest v1alpha5 — 2026-06-10

File kindPredecessorMigration modeFixture
Role manifest (jackin.role.toml)v1alpha4Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-role migrate <role-repo-path>crates/jackin/tests/fixtures/migrations/manifest/from-v1alpha4/meta.toml

Summary: adds optional [<agent>.providers.<id>] tables to the [claude], [codex], and [opencode] agent configs for per-provider model overrides. The providers map is an additive field with a serde default of empty, so existing manifests round-trip cleanly and the migration is a no-op restamp. A manifest stamped older than v1alpha5 that uses a providers table is rejected with a jackin role migrate hint, the same way the OpenCode (v1alpha3) and Kimi (v1alpha4) agent fields are gated.

Before (v1alpha4 manifest):

version = "v1alpha4"

[opencode]
model = "zai-coding-plan/glm-5.1"

After (v1alpha5 — no change needed; the providers map defaults to empty):

version = "v1alpha5"

[opencode]
model = "zai-coding-plan/glm-5.1"

Example with a per-provider override (a role pins a model when MiniMax is picked for OpenCode):

version = "v1alpha5"

[opencode]
model = "zai-coding-plan/glm-5.1"

[opencode.providers.minimax]
model = "minimax/MiniMax-M3"

v1alpha6 — 2026-06-04

File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha5Automatic on startupcrates/jackin/tests/fixtures/migrations/config/from-v1alpha5/meta.toml
Workspace (workspaces/<name>.toml)v1alpha5Automatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-v1alpha5/meta.toml

Summary: adds the optional sync_source_dir field to AgentAuthConfig for per-scope auth-sync source folders. This is an additive, Option-typed field with a serde default of None, so all existing config and workspace files round-trip cleanly through the migration without any transformation. The migration is a no-op restamp.

When sync_source_dir is set, the sync auth mode copies credentials from the operator-chosen agent credential/config folder instead of the per-agent hardcoded default (~/.claude, ~/.codex, ~/.local/share/amp, ~/.kimi-code, ~/.local/share/opencode). For Amp, that folder is the amp directory under XDG_DATA_HOME, not XDG_DATA_HOME itself. Absence means "inherit from the next lower layer → hardcoded default." The field is resolved by jackin_config::resolve_sync_source_dir(cfg, agent, workspace, role) — the same three-layer precedence as resolve_mode.

Before (v1alpha5 config with Claude sync mode):

version = "v1alpha5"

[claude]
auth_forward = "sync"

After (v1alpha6 — no change needed; sync_source_dir defaults to None):

version = "v1alpha6"

[claude]
auth_forward = "sync"

Example with explicit source folder (operator sets a company-specific folder):

version = "v1alpha6"

[claude]
auth_forward = "sync"
sync_source_dir = "/Users/alice/company/.claude"

Workspace v1alpha5 — 2026-05-26

File kindPredecessorMigration modeFixture
Workspace (workspaces/<name>.toml)v1alpha4Automatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-v1alpha4/meta.toml

Summary: moves the workspace-level op_account onto each op:// env reference as a per-ref account key, then removes the top-level op_account. A workspace can hold references from different 1Password accounts; a single workspace-level account cannot serve them, so a reference whose vault lives in a non-default account previously failed to resolve. Each reference now records the account it was created under, and reads pin to it. The migration walks [env], every [roles.<role>.env], [github.env], and every [roles.<role>.github.env] table, stamping account onto each op reference; plain string values are untouched. A workspace with no op_account is a no-op restamp.

Before (v1alpha4 workspace):

version = "v1alpha4"
workdir = "/workspace/prod"
op_account = "ACCT123"

[env]
CLAUDE_CODE_OAUTH_TOKEN = { op = "op://v/i/f", path = "Vault/Item/Field" }
PLAIN_ENV = "literal-value"

After (v1alpha5):

version = "v1alpha5"
workdir = "/workspace/prod"

[env]
CLAUDE_CODE_OAUTH_TOKEN = { op = "op://v/i/f", path = "Vault/Item/Field", account = "ACCT123" }
PLAIN_ENV = "literal-value"

Config v1alpha5 — 2026-05-17

File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha4Automatic on startupcrates/jackin/tests/fixtures/migrations/config/from-v1alpha4/meta.toml

Summary: Introduces the [git] table with two independent boolean fields (both default false): coauthor_trailer enables Co-authored-by agent trailer injection, and dco enables Signed-off-by DCO injection. When either flag is enabled, jackin installs a prepare-commit-msg hook inside containers via core.hooksPath; each trailer is injected only when its corresponding flag is set, and both are deduplicated. The migration is a no-op restamp.

Before (v1alpha4 config):

version = "v1alpha4"

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

After (v1alpha5):

version = "v1alpha5"

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

v1alpha4 — 2026-05-17

File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha3Automatic on startupcrates/jackin/tests/fixtures/migrations/config/from-v1alpha3/meta.toml
Workspace (workspaces/<name>.toml)v1alpha3Automatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-v1alpha3/meta.toml
Manifest (jackin.role.toml)v1alpha3Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-role migrate <role-repo-path>crates/jackin/tests/fixtures/migrations/manifest/from-v1alpha3/meta.toml

Summary: formalizes Kimi agent support after v1alpha3 shipped with OpenCode. The kimi enum variant in agents, the [kimi] manifest table, and the [kimi] auth config tables require v1alpha4; older-stamped files still load as long as they do not use Kimi-specific fields. The migration is a no-op restamp: no field renames, no data moved.

Before (v1alpha3 manifest with Kimi):

version = "v1alpha3"
dockerfile = "Dockerfile"
agents = ["claude", "kimi", "opencode"]

[claude]
plugins = []

[kimi]
model = "kimi-k2"

[opencode]
model = "zai-coding-plan/glm-5.1"

After (v1alpha4):

version = "v1alpha4"
dockerfile = "Dockerfile"
agents = ["claude", "kimi", "opencode"]

[claude]
plugins = []

[kimi]
model = "kimi-k2"

[opencode]
model = "zai-coding-plan/glm-5.1"

v1alpha3 — 2026-05-14

File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha2Automatic on startupcrates/jackin/tests/fixtures/migrations/config/from-v1alpha2/meta.toml
Workspace (workspaces/<name>.toml)v1alpha2Automatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-v1alpha2/meta.toml
Manifest (jackin.role.toml)v1alpha2Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-role migrate <role-repo-path>crates/jackin/tests/fixtures/migrations/manifest/from-v1alpha2/meta.toml

Summary: formalizes OpenCode agent support. The opencode enum variant in agents, the [opencode] manifest table, and the [opencode] auth config tables require v1alpha3; older-stamped files still load as long as they do not use OpenCode-specific fields. 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"

v1alpha2 — 2026-05-11

File kindPredecessorMigration modeFixture
Config (config.toml)v1alpha1Automatic on startupcrates/jackin/tests/fixtures/migrations/config/from-v1alpha1/meta.toml
Workspace (workspaces/<name>.toml)v1alpha1Automatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-v1alpha1/meta.toml
Manifest (jackin.role.toml)v1alpha1Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-role migrate <role-repo-path>crates/jackin/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"

v1alpha1 — 2026-05-10

File kindPredecessorMigration modeFixture
Config (config.toml)legacyAutomatic on startupcrates/jackin/tests/fixtures/migrations/config/from-legacy/meta.toml
Workspace (workspaces/<name>.toml)legacyAutomatic on startupcrates/jackin/tests/fixtures/migrations/workspace/from-legacy/meta.toml
Manifest (jackin.role.toml)legacyDesktop: jackin role migrate <role-repo-path>; CI/automation: jackin-role migrate <role-repo-path>crates/jackin/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

Version format

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.

config.toml

legacy

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.

v1alpha6

FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha6
[claude].auth_forwardstringNolegacysync, api_key, oauth_token, or ignore
[claude].sync_source_dirstringNov1alpha6Host folder override for sync auth forwarding; omitted means use the per-agent default
[codex].auth_forwardstringNolegacysync, api_key, or ignore
[codex].sync_source_dirstringNov1alpha6Host folder override for sync auth forwarding; omitted means use the per-agent default
[amp].auth_forwardstringNolegacysync, api_key, or ignore
[amp].sync_source_dirstringNov1alpha6Host folder override for sync auth forwarding; omitted means use the per-agent default
[kimi].auth_forwardstringNov1alpha4sync, api_key, or ignore
[kimi].sync_source_dirstringNov1alpha6Host folder override for sync auth forwarding; omitted means use the per-agent default
[opencode].auth_forwardstringNov1alpha3sync, api_key, or ignore
[opencode].sync_source_dirstringNov1alpha6Host folder override for sync auth forwarding; omitted means use the per-agent default
[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
[git].coauthor_trailerboolNov1alpha5Enable Co-authored-by agent trailer via prepare-commit-msg hook; omitted when false
[git].dcoboolNov1alpha5Enable Signed-off-by DCO trailer via prepare-commit-msg hook; omitted when false
[workspaces]tableNolegacyLegacy read-only compatibility location; migrated into workspace files

Full operator configuration examples live in Configuration File.

Workspace files

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

legacy

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.

v1alpha6

FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha6
workdirstringYeslegacyContainer working directory
allowed_rolesstring arrayNolegacyRoles allowed in this workspace
default_rolestringNolegacyPreferred role for new sessions
default_agentstringNolegacyclaude, codex, amp, kimi, or opencode; omitted lets launch resolution use the role manifest or prompt
last_rolestringNolegacyLast role selected by the operator
git_pull_on_entryboolNolegacyPull mounted repositories on entry
[env]tableNolegacyWorkspace operator env layer; each op:// reference carries an optional account (the 1Password account it resolves against), since v1alpha5
[[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
[claude].sync_source_dirstringNov1alpha6Workspace Claude host folder override for sync auth forwarding
[codex].auth_forwardstringNolegacyWorkspace Codex auth override
[codex].sync_source_dirstringNov1alpha6Workspace Codex host folder override for sync auth forwarding
[amp].auth_forwardstringNolegacyWorkspace Amp auth override
[amp].sync_source_dirstringNov1alpha6Workspace Amp host folder override for sync auth forwarding
[kimi].auth_forwardstringNov1alpha4Workspace Kimi auth override
[kimi].sync_source_dirstringNov1alpha6Workspace Kimi host folder override for sync auth forwarding
[opencode].auth_forwardstringNov1alpha3Workspace OpenCode auth override
[opencode].sync_source_dirstringNov1alpha6Workspace OpenCode host folder override for sync auth forwarding
[github].auth_forwardstringNolegacyWorkspace GitHub auth override
[github.env]tableNolegacyWorkspace GitHub token env values; op:// references carry the per-ref account since v1alpha5
[roles.<role>.env]tableNolegacyPer-workspace, per-role env override; op:// references carry the per-ref account since v1alpha5
[roles.<role>.claude].auth_forwardstringNolegacyPer-workspace, per-role Claude auth override
[roles.<role>.claude].sync_source_dirstringNov1alpha6Per-workspace, per-role Claude host folder override for sync auth forwarding
[roles.<role>.codex].auth_forwardstringNolegacyPer-workspace, per-role Codex auth override
[roles.<role>.codex].sync_source_dirstringNov1alpha6Per-workspace, per-role Codex host folder override for sync auth forwarding
[roles.<role>.amp].auth_forwardstringNolegacyPer-workspace, per-role Amp auth override
[roles.<role>.amp].sync_source_dirstringNov1alpha6Per-workspace, per-role Amp host folder override for sync auth forwarding
[roles.<role>.kimi].auth_forwardstringNov1alpha4Per-workspace, per-role Kimi auth override
[roles.<role>.kimi].sync_source_dirstringNov1alpha6Per-workspace, per-role Kimi host folder override for sync auth forwarding
[roles.<role>.opencode].auth_forwardstringNov1alpha3Per-workspace, per-role OpenCode auth override
[roles.<role>.opencode].sync_source_dirstringNov1alpha6Per-workspace, per-role OpenCode host folder override for sync auth forwarding
[roles.<role>.github].auth_forwardstringNolegacyPer-workspace, per-role GitHub auth override
[roles.<role>.github.env]tableNolegacyPer-workspace, per-role GitHub token env values; op:// references carry the per-ref account since v1alpha5

jackin.role.toml

legacy

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-role 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

v1alpha4

FieldTypeRequiredSinceNotes
versionstringYesv1alpha1Current value: v1alpha4
dockerfilestringYeslegacyRelative path to role Dockerfile
published_imagestringNolegacyPre-built role image override
agentsstring arrayNolegacyclaude, codex, or amp; opencode added in v1alpha3; kimi added in v1alpha4; 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
[kimi].modelstringNov1alpha4Kimi model override passed to kimi --model
[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.

Migration retention

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:

On this page