Airskills Docs

How sync state works

What the CLI remembers between runs — the .airskills-sync file and why it matters

You usually never think about this — the CLI just tracks what it needs and quietly does the right thing. This page is for when something looks odd and you want to know why.

What the CLI remembers

At the root of your skills directory there's a .airskills-sync file. It stores, for each skill on this machine:

  • The skill_id (the skill's permanent UUID — never changes)
  • The last content the CLI saw (as a hash), so it can tell if you edited the skill since the last push
  • The head_commit_id (the SHA of the newest server commit it saw for this skill), used for conflict detection
  • The resolved_hash (sourced skills only) — the upstream content hash the user last reviewed against. See customisation.

You don't edit this file by hand. The CLI keeps it correct on every push, pull, sync, and resolve.

Why it matters

The sync markers are what let the CLI answer three questions quickly, without asking the server anything:

  • Has this skill changed locally since I last synced it? (yes if current files don't match the stored hash)
  • Has the server moved on since I last saw it? (yes if the server's head_commit_id doesn't match the stored one)
  • Did both of us edit it? (both answers yes = conflict)

That third case is the one to care about. If both sides changed, the CLI does not silently pick a winner. It saves the remote version into a temporary folder and points your agent at both, so the agent can read through them and explain what changed in plain language. You decide what to keep — see incorporation.

The state of every skill

Each skill on your machine is in one of these observable states. The classifier underneath produces this taxonomy; airskills list and airskills doctor both surface it.

StateWhat it meansNext step
syncedLocal matches remote, marker tracks.Nothing — you're done.
modifiedLocal has diverged from the marker. For owned skills this means you have unpublished changes. For sourced skills it means you've customised it — see customisation.Owned: airskills push. Sourced: see below.
modified, pending review (modified*)Sourced skill, local has been customised, AND the original has moved since you last resolved. Something new to look at.Review and airskills resolve (with or without edits), or airskills add <owner>/<skill> --force to drop your customised copy.
untrackedLocal skill directory exists, but airskills has no record of installing it. Common when a skill arrived via git rather than airskills add.airskills sync will either silently link it (if bytes match the server's copy) or surface a conflict for you to resolve.
linkedTransient state during a sync — local matched the server's bytes exactly, so airskills claimed it without downloading. Goes back to synced on the next sync.Nothing.
— (not local)Skill exists on the server, not installed here.airskills add or airskills sync.

The two states that didn't exist before this design — untracked and the pending/resolved split inside modified — are what make customisation observable. A sourced skill is no longer just "modified"; it's either "you've reviewed and chose your customised copy" or "there's something new in the original you haven't seen". The CLI can be quiet about the first and loud about the second.

The three commands that read or write sync state

  • airskills push uses the stored hash to pick which skills actually changed, and sends the stored head_commit_id as X-Expected-Commit so the server can detect a concurrent push.
  • airskills pull fetches the latest head_commit_id for each tracked skill and downloads any that moved. Because the CLI fetches by skill_id, a rename on the owner's side is picked up transparently — the new name comes back as metadata, the skill keeps flowing.
  • airskills status compares on-disk content against the markers without any network call. Useful when you just want to know "did I change anything since last time?" on the plane.

If the sync file gets lost

If you delete .airskills-sync or move to a fresh machine, nothing breaks — the CLI treats every skill as new and re-syncs on the next push/pull, picking up the existing server-side skill by matching skill_ids back to local directories. Conflict detection is weaker in this window (no local hash to compare), but content is never lost; the remote always lands in a temporary folder for you to read through and incorporate.


Deep dive: the marker schema

For curious developers — skip if you just want to use it.

.airskills-sync is a JSON file with a Skills map keyed on local directory name. Each entry looks like:

{
  "SkillID":      "7a3f...",
  "Version":      "1.2.5",
  "ContentHash":  "sha256:...",
  "ResolvedHash": "sha256:...",
  "Tool":         "claude-code",
  "Source":       { "Owner": "chrismdp", "Slug": "code-review" },
  "Deleted":      false,
  "MovedTo":      ""
}
  • SkillID is the stable identity. Pull resolves by this, not by name, which is what makes owner-side rename consumer-transparent.
  • Source is only populated for skills installed via airskills add (sourced from another user's namespace). It keeps the original Owner/Slug for display and anonymous-pull resolution.
  • ResolvedHash is the last upstream content hash you reviewed against via airskills resolve. Only meaningful for sourced skills (where there's an "upstream" distinct from yourself). The classifier compares this to the current upstream hash to decide between modified and modified-pending.
  • Deleted / MovedTo track tombstone state after rm or a server-side transfer.

The CLI writes this atomically (temp file + rename) to avoid leaving a half-written marker if interrupted mid-sync.

Was this page helpful?