objectstack-ai/objectstack/objectstack-upgrade

Claude Code and agent skill by objectstack-ai/objectstack

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Upgrade an ObjectStack metadata project across a protocol major — run the deterministic conversion chain, then work the semantic residue the chain cannot express (intent choices, custom code on retired APIs, stale prose) to a decision with the project's owner, and finish with a green `validate` plus a human-readable upgrade report. Use when a project is on an older protocol major and must move to the current one, when `@objectstack/spec` was bumped across a major and metadata or code stopped pa…

Install

npx vskill@latest install objectstack-ai/objectstack/objectstack-upgrade

SKILL.md

Upgrading an ObjectStack metadata project across a protocol major

preflight → mechanical chain → semantic residue → acceptance report

⛔ The boundary — read this before the first command

Never hand-write a rewrite the chain already applies. If a key was renamed, the conversion table knows the rename; running the chain attributes each rewrite to a hop and proves the result is schema-valid. A hand-edit does neither, and it silently diverges the moment the chain gains an entry.

Never add a tolerant read to make old metadata load. No ?? alias, no "accept both spellings" branch, no coercion in the project's own code. A key was retired because nothing enforced it or because exactly one spelling survives; re-admitting the old one at the consumer is how the defect the retirement closed comes back inside the customer's repo, where no gate can see it.

Never resolve a residue item by guessing the owner's intent. The residue exists precisely because it is a business decision. The rule for when you decide alone and when you ask is in Layer 2 — it is the most important paragraph in this skill.

Never report "upgraded" without the acceptance artifacts. validate green plus the report is the machine criterion. Absent either, the status is in progress, whatever the diff looks like.

One `conversionId` per commit, where the project's review culture allows it. The id is the commit's subject line and its justification.


Quickstart

bash
# 0 · preflight — what major is this project on, what major is installed?
grep -rn "protocol" objectstack.config.ts package.json | head
node -p "require('@objectstack/spec/package.json').version"
# 1 · mechanical — replay the chain (writes only --out; --write also rewrites the sites it can prove)
os validate > .upgrade/validate-before.txt 2>&1 || true # the control, kept
os migrate meta --from 16 --step
os migrate meta --from 16 --json > .upgrade/migrate.json
os migrate meta --from 16 --out .upgrade/migrated.stack.json
# 2 · semantic residue — harvest the prescriptions, then work each item
node -e "console.log(require('fs').readFileSync(require.resolve('@objectstack/spec/package.json').replace('package.json','spec-changes.json'),'utf8'))" > .upgrade/spec-changes.json
# 3 · acceptance — all four, not three
os validate # green (compare against validate-before.txt)
tsc --noEmit # tombstones type the retired keys as `never`
os migrate meta --from 16 --to 18 --json # `applied` [] and no `replayedNothing` (see §3.3)
# → write .upgrade/REPORT.md (template in §3.4)

0 · Preflight

Establish the FROM major — do not guess it

--from is the protocol major the metadata was authored against, not the one installed. Three sources, in order of authority:

  1. `manifest.engines.protocol` in the stack config — the declared answer,

checked by the boot handshake. It is a range, not a version: every scaffold and example writes the caret form (engines: { protocol: '^18' }), and an exact '16.0.0' is only a range of one. Take the major it targets — the floor: '^17' → --from 17, '>=15 <18' → --from 15, never the upper bound.

  1. The last `@objectstack/spec` major the project ever installed — read the

lockfile history (git log -p pnpm-lock.yaml | grep -m5 '@objectstack/spec') when the manifest is absent or stale.

  1. Ask. A manifest that says 16 on a project last touched two years ago is a

claim, not a measurement. If (1) and (2) disagree, settle it — ⛔ never default to the lower one: a default flip (3.3) stamps its constraint onto a source already past that major.

Arriving several majors late is the designed-for case: os migrate meta --from 16 replays every step in order, with no requirement to upgrade one major at a time — down to the chain's support floor, 16 today.

Make the work reviewable before you change anything
bash
git checkout -b upgrade/protocol-17
mkdir -p .upgrade

The .upgrade/ directory is the deliverable's workspace: the machine outputs (migrate.json, migrated.stack.json, spec-changes.json, retired-names.txt) and the human output (REPORT.md). Keeping them in the repo for the review, and deleting them on merge, is the usual arrangement — decide it with the owner.

Re-install the skills from the moved catalog

A 17.x project's skills came from skills add; their skills-lock.json entries read sourceType: github, so the sync skips them (exit 0) and the agent keeps reading 17.x skill text. Remove them (a missing name is skipped; objectstack-pm-dispatch is not in the 18 catalog, only an older install has it), add @objectstack/skills at the installed spec's version with the manager that installed the project, copy it:

bash
npx skills remove objectstack-ai objectstack-api objectstack-automation \
objectstack-data objectstack-formula objectstack-i18n objectstack-platform \
objectstack-pm-dispatch objectstack-query objectstack-ui objectstack-upgrade objectui -y
pnpm add -D "@objectstack/skills@$(node -p "require('@objectstack/spec/package.json').version")"
# npm: npm install --save-dev "@objectstack/skills@…" · yarn: yarn add -D "@objectstack/skills@…"
npx skills@1.7.2 experimental_sync --agent claude-code --copy -y

1 · Mechanical layer — invoke the chain

What os migrate meta actually does
bash
os migrate meta --from 16 # replay 16 → current
os migrate meta --from 16 --step # per-hop checkpoint (bisect a failure)
os migrate meta --from 16 --to 17 # stop at a specific major
os migrate meta --from 16 --json # machine-readable result
os migrate meta --from 16 --out migrated.json # write the canonicalized stack
os migrate meta --from 16 --write # rewrite the proven sites in place
os migrate meta --from 16 apps/crm/objectstack.config.ts # pick the stack explicitly

It loads the stack config, normalizes it without applying the load-time conversion pass, replays each major's conversions as a chain hop, and then parses the result against the current schema to prove the output is valid. What it prints:

  • `Applied N mechanical change(s)` — one line per rewritten site, as

path: from → to (conversionId). This is the diff, already attributed.

  • `N manual change(s) require your judgment` — the chain's semantic entries

for the majors you crossed, each with a why and a verify line. These are Layer 2's input, not a warning to dismiss.

  • `Migrated stack is schema-valid` — or the warning that it is not yet,

which means a residue item is still blocking the parse.

⚠ The one fact that surprises every operator

By default `os migrate meta` rewrites no source file. It lists the mechanical edits and writes only the --out JSON snapshot. --write rewrites in place each edit it can trace to one literal in one project file, lists every other with the reason it was not written, never writes a semantic change, and if re-running the chain over the written files disagrees, restores every file and exits 1.

Stored rows: rehydration replays what the release carries

A deployment's sys_metadata rows are the other subject. At read time the metadata loader and the ObjectQL plugin pass each stored row through applyConversionsToStoredItem, which replays every conversion the release still carries, including entries retired from the load path. 18.3 drops those retired at or below 16.x, so a row still in such a shape is no longer rewritten.

Rehydration is a read-time projection: the rows on disk keep their old shape, and you never hand-edit sys_metadata. ⛔ Run the stored pass before you move (on 18.2 or earlier for such a row) — read-only by default:

``bash os migrate meta --stored # preview, writes nothing os migrate meta --stored --type view --type object # narrow the pass os migrate meta --stored --apply --yes # rewrite the rows ``

⛔ `--yes` is not optional for you. Without it --apply asks for confirmation, and in any non-TTY — every agent session — it refuses instead, exiting 1 with confirmation_required.

--stored takes no --from: a stored row carries its own history, so the pass replays the whole chain.

Data migrations are not metadata migrations

When the chain crosses into a major carrying per-deployment data gates, the run ends by naming each one, what staying un-run costs, and that --apply is the only writing mode. Read that output rather than re-deriving it. What it cannot tell you is whether they have run: that happens against each deployment's own database, and nothing in the metadata upgrade observes it.

⛔ Carry every gate the run printed into the report as `pending`, by name. A gate nobody was told about is served by nobody.


2 · Semantic residue — the part that is yours

A conversion can rename a key, drop a dead one, or lift a value onto its declared block. It cannot make a decision. Everything it cannot do lands here.

2.1 Harvest the instruction sources — all of them ship

The prescriptions are not on a docs site you have to be online for. They ship inside the installed package. Measured against the published @objectstack/spec file list:

SourceWhere, in a consumer projectCarries
Chain resultos migrate meta --from N --json → .specChangesThe conversions + semantic entries for exactly the majors you cross. Start here — it is computed from the installed spec, so it can never be stale.
D4 projectionnode_modules/@objectstack/spec/spec-changes.jsonThe same data for every major, offline: perMajor[].converted and perMajor[].migrated.
Tombstone prescriptionsnode_modules/@objectstack/spec/json-schema/** and src/**/*.zod.tsEvery retired key's [REMOVED] … fix-it text, greppable.
FROM → TO tablesnode_modules/@objectstack/spec/CHANGELOG.mdThe per-retirement narrative, including the "what to write instead" table. This is why the package ships its changelog.
The error itselfYour parse / tsc outputThe same prescription string, delivered at the moment you hit it.
bash
# every tombstone prescription the installed spec carries, deduped (`| wc -l` sizes it)
grep -rho '\[REMOVED\][^"]*' node_modules/@objectstack/spec/json-schema/ | sort -u
# protocol version, support floor, and this crossing's conversion / semantic counts
node -e "
const p = require.resolve('@objectstack/spec/package.json');
const j = require(p.replace('package.json','spec-changes.json'));
const to = parseInt(j.protocolVersion, 10);
const e = j.perMajor.find(x => x.to === to);
console.log(j.protocolVersion, 'floor', j.supportFloor, '| →', to + ':',
e.converted.length, 'converted,', e.migrated.length, 'semantic');
"
# the FROM → TO table for one retired key
grep -n -B4 -A20 'transform' node_modules/@objectstack/spec/CHANGELOG.md | less

⛔ Never carry a remembered count or a pinned table into the report. Every number here is a reading of this install; measure it at the start of the upgrade and again in the report.

Not reachable from a consumer project, so do not send anyone there: the
conversion and migration registries (src/conversions/registry.ts,
src/migrations/registry.ts) and the platform repo's generated upgrade guide
are not in the published package — only src/**/*.zod.ts is.
2.2 The three residue classes

R1 · Intent choice — a key was retired with no single lossless target. The conversion drops the key (so the project parses) and, where it matters, emits a notice naming the site. What the key was for still has to go somewhere, and where is a business statement.

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
76
Repository forks
20
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/objectstack-ai/objectstack/objectstack-upgrade/badge)](https://verified-skill.com/skills/objectstack-ai/objectstack/objectstack-upgrade)

Something wrong with this skill or its page? Tell us.