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
Section titled “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
versionstamp. When jackin reads the file, it compares the on-disk version against the binary’sCURRENT_*_VERSIONand applies any pending migration steps before parsing, so operators see a working setup after every upgrade. - Operator-owned files migrate automatically.
config.tomland~/.config/jackin/workspaces/<name>.tomlare 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 ajackin.role.tomlagainst 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 standalonejackin-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 inAGENTS.mdandPULL_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
versionis 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-specificjackin 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
Section titled “Current versions”| File | Current version | Owner | Migration mode |
|---|---|---|---|
~/.config/jackin/config.toml | v1alpha2 | jackin | Automatic on startup |
~/.config/jackin/workspaces/<name>.toml | v1alpha2 | jackin | Automatic on startup |
jackin.role.toml | v1alpha3 | Role repository | Desktop: jackin role migrate <role-repo-path>; CI/automation: jackin-validate --migrate <role-repo-path> |
Timeline
Section titled “Timeline”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.
v1alpha3 — 2026-05-14
Section titled “v1alpha3 — 2026-05-14”| File kind | Predecessor | Migration mode | Fixture |
|---|---|---|---|
Manifest (jackin.role.toml) | v1alpha2 | Desktop: 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"v1alpha2 — 2026-05-11
Section titled “v1alpha2 — 2026-05-11”| File kind | Predecessor | Migration mode | Fixture |
|---|---|---|---|
Config (config.toml) | v1alpha1 | Automatic on startup | tests/fixtures/migrations/config/from-v1alpha1/meta.toml |
Workspace (workspaces/<name>.toml) | v1alpha1 | Automatic on startup | tests/fixtures/migrations/workspace/from-v1alpha1/meta.toml |
Manifest (jackin.role.toml) | v1alpha1 | Desktop: 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"v1alpha1 — 2026-05-10
Section titled “v1alpha1 — 2026-05-10”| File kind | Predecessor | Migration mode | Fixture |
|---|---|---|---|
Config (config.toml) | legacy | Automatic on startup | tests/fixtures/migrations/config/from-legacy/meta.toml |
Workspace (workspaces/<name>.toml) | legacy | Automatic on startup | tests/fixtures/migrations/workspace/from-legacy/meta.toml |
Manifest (jackin.role.toml) | legacy | Desktop: 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 = trueAfter (v1alpha1):
version = "v1alpha1"
[roles.agent-smith]git = "https://github.com/jackin-project/jackin-agent-smith.git"trusted = trueVersion format
Section titled “Version format”Schema versions use Kubernetes-style names:
| Form | Meaning |
|---|---|
v1alpha1 | Unstable schema for the future stable v1 family |
v1alpha2 | Next unstable schema in the same family |
v1beta1 | More mature but still not stable |
v1 | Stable schema |
The current project is still unstable, so all current schemas use the v1alpha* family.
config.toml
Section titled “config.toml”legacy
Section titled “legacy”legacy means the file has no top-level version field. For operator
config, jackin migrates this automatically before parsing.
Change to v1alpha1 | Detail |
|---|---|
| Added | version = "v1alpha1" |
| Preserved | Global agent auth, GitHub auth, env, role sources, Docker mounts |
| Removed | None |
| Renamed | None |
The split-from-config.toml work for legacy [workspaces.<name>] tables runs as a separate startup migration alongside the version stamp; see Configuration File.
v1alpha2
Section titled “v1alpha2”| Field | Type | Required | Since | Notes |
|---|---|---|---|---|
version | string | Yes | v1alpha1 | Current value: v1alpha2 |
[claude].auth_forward | string | No | legacy | sync, api_key, oauth_token, or ignore |
[codex].auth_forward | string | No | legacy | sync, api_key, or ignore |
[amp].auth_forward | string | No | legacy | sync, api_key, or ignore |
[opencode].auth_forward | string | No | legacy | sync, api_key, or ignore |
[github].auth_forward | string | No | legacy | sync, token, or ignore |
[github.env] | table | No | legacy | Operator env values for GitHub token auth |
[env] | table | No | legacy | Global operator env layer |
[roles.<role>] | table | No | legacy | Role source config |
[roles.<role>].git | string | Yes when role is declared | legacy | Role repository URL |
[roles.<role>].trusted | bool | No | legacy | Trust-on-first-use state |
[roles.<role>.env] | table | No | legacy | Per-role operator env layer |
[docker.mounts] | table | No | legacy | Global and scoped Docker mount config |
[workspaces] | table | No | legacy | Legacy read-only compatibility location; migrated into workspace files |
Full operator configuration examples live in Configuration File.
Workspace files
Section titled “Workspace files”Workspace files live at ~/.config/jackin/workspaces/<name>.toml.
legacy
Section titled “legacy”legacy means either a standalone workspace file with no version, or
a [workspaces.<name>] table embedded in legacy config.toml.
Change to v1alpha1 | Detail |
|---|---|
| Added | version = "v1alpha1" |
| Preserved | Workdir, mounts, role selection, env, auth overrides, keep-awake, 1Password account |
| Removed | None |
| Renamed | None |
Legacy embedded [workspaces.<name>] tables in config.toml are split into per-workspace files by a separate startup migration; see Configuration File.
v1alpha2
Section titled “v1alpha2”| Field | Type | Required | Since | Notes |
|---|---|---|---|---|
version | string | Yes | v1alpha1 | Current value: v1alpha2 |
workdir | string | Yes | legacy | Container working directory |
allowed_roles | string array | No | legacy | Roles allowed in this workspace |
default_role | string | No | legacy | Preferred role for new sessions |
default_agent | string | No | legacy | claude, codex, amp, or opencode; omitted defaults to Claude |
last_role | string | No | legacy | Last role selected by the operator |
op_account | string | No | legacy | 1Password account selector |
git_pull_on_entry | bool | No | legacy | Pull mounted repositories on entry |
[env] | table | No | legacy | Workspace operator env layer |
[[mounts]] | array of tables | No | legacy | Workspace mounts |
[[mounts]].src | string | Yes | legacy | Host path |
[[mounts]].dst | string | Yes | legacy | Container path |
[[mounts]].readonly | bool | No | legacy | Defaults to false |
[[mounts]].isolation | string | No | legacy | shared, worktree, or clone; legacy default is shared |
[keep_awake].enabled | bool | No | legacy | macOS keep-awake toggle |
[claude].auth_forward | string | No | legacy | Workspace Claude auth override |
[codex].auth_forward | string | No | legacy | Workspace Codex auth override |
[amp].auth_forward | string | No | legacy | Workspace Amp auth override |
[opencode].auth_forward | string | No | legacy | Workspace OpenCode auth override |
[github].auth_forward | string | No | legacy | Workspace GitHub auth override |
[github.env] | table | No | legacy | Workspace GitHub token env values |
[roles.<role>.env] | table | No | legacy | Per-workspace, per-role env override |
[roles.<role>.claude].auth_forward | string | No | legacy | Per-workspace, per-role Claude auth override |
[roles.<role>.codex].auth_forward | string | No | legacy | Per-workspace, per-role Codex auth override |
[roles.<role>.amp].auth_forward | string | No | legacy | Per-workspace, per-role Amp auth override |
[roles.<role>.opencode].auth_forward | string | No | legacy | Per-workspace, per-role OpenCode auth override |
[roles.<role>.github].auth_forward | string | No | legacy | Per-workspace, per-role GitHub auth override |
[roles.<role>.github.env] | table | No | legacy | Per-workspace, per-role GitHub token env values |
jackin.role.toml
Section titled “jackin.role.toml”legacy
Section titled “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-validate --migrate <role-repo-path> in CI and
automated migration jobs.
Change to v1alpha1 | Detail |
|---|---|
| Added | version = "v1alpha1" |
| Moved | None |
| Preserved | Dockerfile, published image, identity, agents, runtime settings, hooks, env prompts |
| Removed | None |
| Renamed | None |
v1alpha3
Section titled “v1alpha3”| Field | Type | Required | Since | Notes |
|---|---|---|---|---|
version | string | Yes | v1alpha1 | Current value: v1alpha3 |
dockerfile | string | Yes | legacy | Relative path to role Dockerfile |
published_image | string | No | legacy | Pre-built role image override |
agents | string array | No | legacy | claude, codex, or amp; opencode added in v1alpha3; omitted means Claude-only |
[identity].name | string | No | legacy | Display name |
[claude].model | string | No | legacy | Claude model override |
[claude].plugins | string array | No | legacy | Claude plugin identifiers |
[[claude.marketplaces]] | array of tables | No | legacy | Claude plugin marketplace registrations |
[[claude.marketplaces]].source | string | Yes | legacy | Marketplace source |
[[claude.marketplaces]].sparse | string array | No | legacy | Sparse checkout paths |
[codex].model | string | No | legacy | Codex model override |
[amp] | table | No | legacy | Empty marker table for Amp support |
[opencode].model | string | No | v1alpha3 | OpenCode model override in provider/model format (e.g. zai-coding-plan/glm-5.1) |
[hooks].setup_once | string | No | legacy | Relative path to a one-time install script that runs on first launch only |
[hooks].source | string | No | legacy | Relative path to a script dot-sourced into the entrypoint shell so export and PATH mutations reach the launched agent |
[hooks].preflight | string | No | legacy | Relative path to a per-start preflight script |
[env.<NAME>] | table | No | legacy | Interactive env prompt declaration |
[env.<NAME>].default | string | No | legacy | Default env value |
[env.<NAME>].interactive | bool | No | legacy | Prompt operator before launch |
[env.<NAME>].skippable | bool | No | legacy | Allow empty response |
[env.<NAME>].prompt | string | No | legacy | Prompt text |
[env.<NAME>].options | string array | No | legacy | Fixed choices |
[env.<NAME>].depends_on | string array | No | legacy | Dependency references such as env.PROJECT |
Full role manifest examples live in Role Manifest.
Migration retention
Section titled “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:
| File kind | Code entry point |
|---|---|
| Config | src/config/migrations.rs |
| Workspace | src/config/migrations.rs |
| Role manifest | src/manifest/migrations.rs |