Skip to content
Get AI Business OS

State Files and Validation

AI Business OS

AI Business OS keeps a register of your projects in one file, .claude/state/state.json. The daily commands read it to brief you and write to it to record what happened, so it is the workspace’s memory of what you are working on. This page explains what the file holds, how AI Business OS forms project IDs, and how backups and validation protect it.

File What it is
.claude/state/state.json The project register. Your file, never changed by /update
.claude/state/state.schema.json The schema that describes a valid register
.claude/state/backups/YYYY-MM-DD.json Daily backups, kept on your computer only
.claude/state/history/YYYY-MM.json The session history archive, one file per month
Scripts/backup-state.sh Makes a backup
Scripts/validate-state.sh Checks the register
Scripts/archive-history.sh Moves older session history into the monthly archive

The same three scripts also ship in Infrastructure/Scripts/prima/, and both copies do the same job. /save uses that copy, and the other commands use the copies in Scripts/.

The register is plain JSON, written with the jq tool through a temporary file, so any agent or editor can read it.

Field What it holds
version The version of the register format. Required
workspace The workspace’s name, id, type and githubRepo. Required
projects One entry per project. Required
nextProjectNumber A counter /newproject takes into account when numbering
sessionHistory Short summaries of this calendar month’s sessions, newest first. Earlier months move to the monthly archive
priorities Lists for immediate, thisWeek and upcoming
pendingItems Open items carried between sessions
recentWork Three to five activities from the latest session, replaced by each /night
selectedCalendars The calendars /day reads, each written as an object with a name and, when known, an id

The workspace type is one of personal, client or internal. The id uses lowercase letters, numbers and hyphens only. /setup fills in the workspace block, and /sync uses githubRepo to check it is pushing to the right repository.

Every project entry needs four fields.

Field Values
id The project ID, such as P012
name The project name, such as Spring Workshop
status in-progress, paused, overdue or archived, and nothing else
category client, product, internal, marketing, research, operations, finance, sales, legal or it

The optional fields are description, priority (high, medium or low), created, dueDate, lastWorked, stoppedAt, lastAction, pausedReason, tags, path, notes, companyName and contacts. In a workspace with the domain layout, /newproject also records a domain.

Some fields have conditions attached.

  • Paused projects. A paused project needs a pausedReason, and every other project has none.
  • Client projects. A project in the client category needs a companyName and at least one name in contacts. Full contact details belong in PRIMA CRM if you use it.
  • Continuity. stoppedAt records where work stopped and lastAction the last thing completed. /night sets them, and stoppedAt clears when the project is next worked on.

A project entry for an invented workspace looks like this.

{
"id": "P012",
"name": "Spring Workshop",
"description": "Plan and deliver the spring workshop for Example Consulting's clients",
"status": "in-progress",
"priority": "medium",
"created": "2026-10-14",
"dueDate": "2027-03-31",
"lastWorked": "2026-10-14",
"stoppedAt": null,
"lastAction": "Project created",
"pausedReason": null,
"category": "internal",
"tags": ["events", "training"],
"path": "Domains/15 Education & Training/P012 Spring Workshop",
"domain": "15 Education & Training",
"notes": ""
}

/newproject takes the ID format from the IDs already in the register.

  1. An empty register. The first project is P001, and numbering continues P002, P003 and so on.
  2. A register in one format. /newproject continues that format, whatever it is. A workspace that already uses PRJ-0001 keeps using it.
  3. A register with two formats. /newproject stops, shows you one example of each, and asks which to use. It creates nothing until you answer.

The new number is the highest existing number plus one, or nextProjectNumber if that is higher. AI Business OS never reuses an ID, even after you archive a project, and never changes an existing ID. If the next number needs more digits than the format allows, such as P1000, /newproject stops and tells you. It does not widen the format.

Command What it does with the register
/setup Writes the workspace block and the selected calendars
/newproject Adds the project entry and moves nextProjectNumber on
/day Reads projects for the briefing, and can archive, pause or resume a project when you ask
/status Reads projects for the report, and can archive a project and move its folder to Archive/
/night Records the session summary, lastWorked, stoppedAt and lastAction
/save Records progress mid-session
/resume Reads where you left off
/dashboard Reads the register to build the HTML dashboard

Before any command writes to the register, it runs the backup script.

Terminal window
bash Scripts/backup-state.sh

The script copies the register to .claude/state/backups/ under the day’s date, such as 2026-10-14.json, and deletes backups older than 30 days.

The session history holds the current calendar month only. After /save and /night write the register, archive-history.sh moves every entry from an earlier month into the archive file for that month, such as .claude/state/history/2026-07.json, so no entry is ever deleted. Each archived entry keeps its date and summary and gains an archivedFrom field that names the workspace or the project it came from. Run bash Scripts/archive-history.sh --dry-run to see what it would move without changing anything.

After every write, the command runs the validation script.

Terminal window
bash Scripts/validate-state.sh

Some problems fail the check, and the command restores the backup and reports the error. Others only print a warning, and /save and /night show every warning in their report so that none goes unseen.

Check Result if it fails
The file is valid JSON Fails
version, workspace and projects are present Fails
The workspace type is personal, client or internal Fails
Every project ID is unique Fails
Every project ID has the form of letters, an optional hyphen, then three to six digits Fails
Every status is one of the four allowed values Fails
The register matches the schema, checked only when the ajv validator is installed Fails
The workspace name, ID and type are all filled in Warning
No two projects share a name Warning
All project IDs use one format Warning
Every project has a valid category Warning
Every paused project has a reason Warning
Session history holds no entries from an earlier month Warning
Every archive file in .claude/state/history/ has an entries list Fails

A clean run ends with a count of projects by status and the line State validation passed. This is the output for the sample register that ships with a new workspace.

JSON syntax valid
Required fields present (version: 1.0.0)
Project IDs unique
Project ID format valid
Status values valid
Projects: 3 total (3 active, 0 paused, 0 overdue, 0 archived)
INFO: ajv-cli not installed — schema validation skipped
State validation passed

If the register is damaged, you can ask Claude to restore it from a backup and name the date you want. To do it yourself, follow these steps from the workspace folder.

  1. List the backups with ls .claude/state/backups/.
  2. Copy the backup you want over the register, for example cp .claude/state/backups/2026-10-13.json .claude/state/state.json.
  3. Run bash Scripts/validate-state.sh and check that it passes.
  4. Commit the restored file with /sync.

You lose any change made to the register after that backup, so check stoppedAt and lastAction on the projects you worked on since.

PRIMA Project Management takes over the state schema, the State Validation rule and the two scripts in Scripts/. See State Files Explained if you have it installed.