apiVersion policy, ID formats, the migration guide, privacy conventions, and the v2 deliverable boundary.
This is the multi-page printable view of this section. Click here to print.
Reference
1 - apiVersion Policy
processkit uses a Kubernetes-style apiVersion field on every entity:
apiVersion: processkit.projectious.work/v1
The group
The group processkit.projectious.work is a reverse-DNS name anchored on
the owning organization (projectious.work) with processkit as a
subcomponent. This prevents name collisions if other organizations fork
or publish compatible primitives under their own domains.
The form <reverse-dns-group>/<version> is the Kubernetes-idiomatic
shape — exactly one slash. Tools that split on / expect exactly two
parts.
Evolution rules
| apiVersion | Status | Meaning |
|---|---|---|
processkit.projectious.work/v1 | current v0.x entity format | Initial public entity version |
processkit.projectious.work/v1beta1 | not used | Reserved |
processkit.projectious.work/v2 | planned | Breaking contract with explicit migration required |
Non-breaking changes (stay at v1)
- Adding new optional fields to schemas
- Adding new primitive kinds
- Adding new states to a state machine
- Adding new skills
- Adding new packages
Breaking changes (require v2)
- Removing or renaming existing fields
- Changing the type or meaning of existing fields
- Removing states from a state machine (stranding existing entities)
- Removing primitive kinds
- Changing the semantics of
metadata.id,metadata.created, or other cross-cutting fields
Migration between versions
The SmoothTiger/SmoothRiver v2 direction is a no-shim contract: v2 schemas and index semantics become authoritative, and processkit does not add hidden dual-read or permissive validation paths for v1 data. Existing v1 contexts remain a migration source, not a long-term compatibility target.
For a v1 context moving to v2:
- The installer or migration tool generates a diff between the old upstream reference templates and the new ones.
- A
Migrationentity records the affected files, source and targetapiVersion, source and target processkit versions, and the proposed plan. - The agent runs the migration through
migration-management, using dry-run diagnostics before applying changes. - The user approves the project-specific plan before the migration
reaches
applied. - After migration, v2 validation rejects unknown kinds, stale primitive assumptions, and ad hoc event/type vocabulary that v1 tolerated.
No automatic in-place patching — migrations always go through an explicit review and approval step. See the v0.25.0 changelog for the public breaking-change summary.
2 - ID Formats
Entity IDs in processkit have the shape <PREFIX>-<id-body>. The prefix
is determined by the primitive kind and is not configurable. The id-body
has two independent configuration axes: format and slug.
Configuration
In the consuming project’s aibox.toml:
[context]
id_format = "word" # word | uuid
id_slug = false # true | false
The four combinations
id_format | id_slug | Example | Notes |
|---|---|---|---|
word | false | BACK-calm-fox | Default. Short, memorable, solo-friendly |
word | true | BACK-calm-fox-add-lint | Memorable + descriptive for prose contexts |
uuid | false | BACK-550e8400-e29b-41d4 | Uniqueness guarantees for large teams |
uuid | true | BACK-550e8400-add-lint | UUID + readable context |
Prefix registry
| Primitive | Prefix |
|---|---|
| WorkItem | BACK |
| LogEntry | LOG |
| DecisionRecord | DEC |
| Migration | MIG |
| Artifact | ART |
| Note | NOTE |
| Actor | ACTOR |
| Role | ROLE |
| Binding | BIND |
| Scope | SCOPE |
| Category | CAT |
| CrossReference | — |
| Gate | GATE |
| Schedule | SCHED (legacy v1) |
| Constraint | CONST |
| Context | CTX |
| Discussion | DISC |
| Process | PROC (legacy v1) |
| StateMachine | SM (legacy v1) |
Metric, Model, Process, Schedule, and StateMachine do not
reserve first-class primitive prefixes in the v2 contract. The legacy
prefixes remain documented so existing v1 contexts can be migrated and
read correctly.
Word generation
Word-based IDs come from the petname
algorithm: one adjective + one noun (or two, depending on
id_format_depth — default 2). Collisions are detected at generation
time and a third component is appended if needed.
Slugs
When id_slug = true, a content-derived slug is appended to the ID body.
For a WorkItem with title “Add release audit check”, the slug would be
add-release-audit-check (first N tokens, kebab-case, truncated).
Slugs are for human readability and do not affect uniqueness — the word or UUID portion still guarantees that.
Choosing a format
- Solo developer:
word+slug: false— shortest, most memorable - Small team with process:
word+slug: true— readable in prose - Large team or automation-heavy:
uuid+slug: true— uniqueness + readability - Automation-only:
uuid+slug: false— machines don’t care about readability
3 - Version Migration
processkit is distributed as versioned releases. Upgrading pinned
versions is deliberate: processkit does not silently rewrite a consuming
project’s context. A version bump should produce a Migration document
under context/migrations/pending/ that the user and agent work through
together.
The model
processkit ships a generic diff script (scripts/processkit-diff.sh) that
compares two tagged versions of any processkit-compatible source — upstream
processkit, a company fork like processkit-acme, or any other downstream.
The script reads src/PROVENANCE.toml at each tag (a single file mapping
every shipped file to the tag in which it last changed) and emits a
structured diff: added, removed, changed, unchanged.
For removed or renamed skills, the JSON and TOML formats also include
cleanup_hints. Installers should treat these as explicit cleanup
instructions for upstream-managed hot files: remove stale skill directories
when remove_skill_directory = true, remove listed generated command
adapters, and surface replacement_path as the canonical successor when
the removal is a rename.
Managed installers can consume this diff model. For example, when
aibox sync notices a new pinned version, it:
Fetches the new tag into
~/.cache/aibox/processkit/<version>/Calls the diff script (or reimplements its logic) to compare the currently-installed version against the new one
For each affected file, computes three SHAs on the fly:
- template SHA — from the verbatim reference at
context/templates/processkit/<current-version>/<file> - cache SHA — what the new upstream version says
- live SHA — what’s actually in the project right now
and uses them to classify the file:
- changed-upstream-only — safe to take with one approval
- changed-locally-only — no-op for this migration
- conflict — both sides changed, must be resolved by hand
- new-upstream — added by upstream, decide whether to take it
- removed-upstream — removed by upstream, decide whether to drop locally
- template SHA — from the verbatim reference at
Writes a
Migrationdocument tocontext/migrations/pending/MIG-<id>.mdcontaining the briefingUpdates
context/migrations/INDEX.mdwith the new pending entryReports the result and stops — never auto-applies
The user reads the briefing, approves a project-specific plan, and the
migration moves through pending/ → in-progress/ → applied/. See the
migration-management skill
for the workflow details.
What’s git-tracked vs cache
| Where | Git status | Purpose |
|---|---|---|
aibox.lock (project root) | tracked | Pinned source URL + version + resolved commit (Cargo-style) |
context/templates/processkit/<v>/... | tracked | Verbatim reference copy of every shipped file (the “as-installed” reference for diffs) |
context/migrations/pending/MIG-*.md | tracked | Pending migration briefings |
context/migrations/in-progress/MIG-*.md | tracked | Migrations being worked through |
context/migrations/applied/MIG-*.md | tracked | Historical record |
context/migrations/INDEX.md | tracked | Always-loaded summary |
context/.cache/processkit/... | NOT tracked | Per-project runtime cache (e.g. SQLite index) |
~/.cache/aibox/processkit/<v>/... | NOT tracked | aibox’s fetched upstream cache, reproducible from the lock |
A new developer cloning the project gets aibox.lock + the reference
templates + migration documents from git. aibox sync fetches the
upstream cache as needed. Everything is reconstructible from the git
checkout.
Upgrading
# aibox.toml
[processkit]
source = "https://github.com/projectious-work/processkit.git"
version = "v0.4.0" # was: "v0.3.0"
src_path = "src" # default — matches upstream layout
Then:
aibox sync # fetches new tag, generates the migration document
aibox migrate # walks through the pending migration with you
<validator> # structural validation after migration is applied
v1 to v2 context migration
The v2 deliverable direction is intentionally breaking: processkit does
not provide compatibility shims that let v1 and v2 contracts coexist
inside the same shipped src/ tree. A live v1 project context is valid
only as a migration source until the generated migration is worked
through.
The explicit path is:
- Keep the live project on its pinned v1 processkit version until
aibox synccreates the v2Migration. - Review the generated briefing, including
source_api_version,target_api_version,source_processkit_version, andtarget_processkit_version. - Run the v2 migration through
migration-managementwith dry-run diagnostics first. - Apply the approved plan, then run structural validation and the processkit smoke checks.
This path is the only supported bridge for v1 contexts. v2 schemas and index semantics are authoritative once the migration is applied.
See the v0.25.0 changelog for the public breaking-change summary.
Configurable source URL
The [processkit] source field accepts any git URL. The default
upstream is https://github.com/projectious-work/processkit.git, but
companies can fork processkit into their own repository, customize it,
and have their projects consume the fork:
[processkit]
source = "https://gitlab.acme.com/platform/processkit-acme.git"
version = "v0.4.0-acme.1"
The fork is responsible for regenerating its own PROVENANCE.toml against
its git history and tagging releases. The diff script and migration model
work identically for forks — they just see the fork’s tags instead of
upstream’s.
For forks pulling from upstream periodically, use the diff script directly:
# Inside the processkit-acme checkout
scripts/processkit-diff.sh --from upstream/v0.4.0 --to upstream/v0.5.0 --format toml > upstream-changes.toml
The maintainer applies the changes to the fork manually, then re-tags as
e.g. v0.5.0-acme.1. ACME’s projects then bump their version and run
aibox sync to pick up the changes.
Pre-v0.4.0 behavior (deprecated)
Versions before v0.4.0 used a simpler model: every project copied the
processkit content into its own files, and aibox migrate produced
text-only migration documents at context/migrations/<from>-to-<to>.md.
This worked but had no concept of provenance, no manifest, and no way to
classify “user-modified vs unchanged” without manual diffing. The v0.4.0
model is a strict superset and is backward-compatible: pre-v0.4.0
migration documents are not touched and remain readable.
What aibox sync will not do
- Auto-overwrite any file the user has touched (per the user-confirmed Strawman D rule)
- Apply changes from a pending migration without explicit user approval
- Re-generate a migration document for a version pair that already has
one in
pending/orin-progress/(it tells the user “pending migration exists, runaibox migrateto work on it”)
Downgrading
Downgrading is supported but discouraged. To downgrade:
[processkit]
version = "v0.3.0" # was: "v0.4.0"
then aibox sync. If the downgrade skips past a schema apiVersion bump,
existing entities may become incompatible with the older schemas.
validation should flag the failures. You may need to manually edit or
delete incompatible entities.
4 - Privacy Tiers
processkit recognizes three privacy tiers for entities under context/.
The tier is declared via an optional privacy: field in metadata and
enforced by directory layout + a .gitignore rule.
The three tiers
| Tier | Default? | Git status | Typical use |
|---|---|---|---|
public | no | tracked | identity.md, README, public roadmap |
project-private | yes (default if omitted) | tracked | workitems, decisions, logs, working-style.md |
user-private | no | NOT tracked | team-and-relationships.md, personal scratch notes |
Most entities omit the field entirely and inherit project-private.
Filesystem rule for user-private
Entities with privacy: user-private MUST live under a directory named
private/ somewhere within context/. Projects should carry a
.gitignore rule like:
context/**/private/
This pattern matches private/ directories at any depth under
context/, including directly under context/ itself. So all of these
are excluded from git:
context/private/context/owner/private/context/foo/bar/private/
But NOT directories named private/ outside context/ (e.g.
cli/src/private/ would NOT be ignored by this rule).
Installers and validation tools should verify that any entity with
privacy: user-private lives under a private/ directory under
context/. A user-private entity outside such a directory is invalid.
Where the convention is used
owner-profilingskill:context/owner/private/team-and-relationships.mdis the canonical example. Notes about coworkers’ communication styles, sensitivities, and interpersonal dynamics should never be checked into a shared repository.- Personal scratch notes: any project can have a
context/private/for personal drafts, half-formed ideas, or session notes that the agent should see but the team should not. - API keys / secrets are NOT what this is for — those should be in environment variables or a secret manager. Privacy tiers are for human-readable content that’s sensitive but not credentialed.
Frontmatter example
---
apiVersion: processkit.projectious.work/v1
kind: Context
metadata:
id: OWNER-team-and-relationships
privacy: user-private
created: 2026-04-07T00:00:00Z
spec:
description: "Per-person notes about collaborators."
---
# Team and Relationships
> ⚠️ PRIVACY: user-private. This file lives under context/owner/private/
> which is gitignored.
...
Why directory enforcement, not just frontmatter
A frontmatter declaration alone wouldn’t prevent the file from being
checked into git — git add doesn’t read frontmatter. The directory rule
gives a hard guarantee via .gitignore. The frontmatter declaration is
documentation + lint validation; the directory placement is the actual
safety mechanism.
If you want a user-private file outside any private/ directory, you
have two options:
- Move it under a
private/directory (correct) - Override the validation rule in local tooling (discouraged because it defeats the safety mechanism)
Public files
privacy: public is documentation, not security — anything in a public
git repo is already world-readable. The distinction between public and
project-private only matters when the project is in a private repo: in
that case public files are fine to syndicate to a public mirror or
include in a generated README, while project-private files are not.
For projects in public repos, public and project-private are
functionally identical.
Docs-site filtering
Projects that build a documentation site from their context content must
exclude private subtrees from the build. For the Hugo site processkit
itself ships, that is a hugo.yaml entry:
ignoreFiles:
- "/private/"
Other generators need the same rule expressed their own way — a
Docusaurus docs preset, for example, takes
exclude: ['**/private/**'].
This is the rule processkit’s own documentation build carries. It
matches private/ directories at any depth, so context/private/,
context/owner/private/, and any deeper nesting are all excluded.
Multi-user projects
For projects where multiple people work from the same repository, the
current convention is flat context/private/: a single gitignored
directory that is personal to whoever is running the agent locally.
A per-user subdirectory convention (context/private/<username>/) is
not yet standardized. The actor primitive (actor-profile) captures
identity but the privacy directory layout does not yet key on it.
Defer the multi-user convention until a real project asks for it —
at that point, context/private/<username>/ is the natural extension
and requires no schema changes, only a new gitignore pattern.
This decision was recorded in response to aibox DEC-030 / processkit#1 .
5 - v2 Contracts
SmoothTiger/SmoothRiver v2 keeps durable facts in existing entity primitives and uses projection skills for runtime files. The source of truth remains processkit context; generated files are checked against that source.
Metric, Model, Process, Schedule, and StateMachine are legacy
v1 migration-source kinds, not shipped v2 entity primitives. Model
selection uses model-recommender roster/configuration data. Process
definitions are Artifacts plus process-instance WorkItems. Schedule
semantics use Binding(type=time-window). Runtime state-machine YAML
files remain implementation contracts, not user-authored StateMachine
entities.
Hook inbox
Hook inbox items are Notes with spec.inbox. The note-management MCP
server owns the lifecycle:
prepare_hook_inbox_dirscapture_inbox_itemclaim_inbox_itemcomplete_inbox_itemfail_inbox_item
Valid injection modes are interrupt, ambient, and next-cycle.
They belong on Binding(type=triage-classification) records.
AgentCard
Agent cards are Artifact-backed projections. Store the canonical source
as an Artifact with spec.kind: agent-card, then use the agent-card
MCP server’s project_agent_card tool to render the public JSON file.
spec.projection_path and spec.projection_checksum let validation
detect missing or stale projections.
Eval gates
The eval-gate-authoring MCP server turns observed run outputs into:
Artifact(spec.kind=eval-spec)- a paired
Gate - policy/application Bindings
- calibration LogEntries for LLM-as-judge evals
Use collect_run_outputs, codify_eval, calibrate_judge, and
bind_eval_to_runs. LLM judge eval specs are expected to have a
calibration log before they are treated as enforceable gates.
Security projections
Security policy sources are Artifacts. The security-projections MCP
server emits runtime policy files from those Artifacts:
project_agent_ids_rulerenders Agent-IDS JSON rules.project_tetragon_tracing_policyrenders Tetragon-style YAML tracing policies.
Keep the Artifact as the reviewable source and treat generated policy files as projections.
pk-doctor v2_contracts
pk-doctor includes a v2_contracts check for v2 workflow and
projection guardrails. It currently checks:
- process-instance WorkItems reference a process definition.
- time-window Bindings include
conditions.recurrence_rule. - cost-policy Artifacts are bound through budget-application Bindings.
- policy supersedes chains point at known policy Artifacts.
- LLM-as-judge eval-spec Artifacts have calibration logs.
- agent-card projections exist and match recorded checksums.
- hook inbox injection modes are valid and scoped to triage-classification Bindings.
- claimed inbox Notes older than 24 hours are reported as orphan risks.
Run it through the normal doctor command:
uv run context/skills/processkit/pk-doctor/scripts/doctor.py