State is a single JSON document validated on every read/write. All object keys in the document must be verbiage keys matching:
^[A-Z]+(-[A-Z]+)*$
Inputs that become keys are normalized (lowercase → UPPERCASE, spaces → dashes, repeated dashes collapsed). Any other characters (digits, underscores, punctuation) are rejected.
Any string value may be treated as an external reference when it uses the form:
ref file://<path>
Where <path> is a local JSON file path. If <path> is relative, it is resolved relative to the directory containing STATE_PATH.
When STATE_PATH is under a directory named state (the default: .../bin/state/state.json), ref targets that begin with state/ are resolved relative to the parent directory. This allows ergonomic shard paths like ref file://state/OPS/QUEUE.json without creating a nested state/state/... folder.
When setting a ref, you can optionally append an initialization payload:
ref file://<path> <json-or-string>
This will:
- Write
<json-or-string>as the referenced file’s root JSON value (overwriting the file). - Store the canonical ref string (
ref file://<path>) in the state (the init payload is stripped).
Notes:
- The URI must not contain raw whitespace when using the init form (use paths without spaces).
- Init is rejected if the file is already mounted by the current ref graph (to avoid accidental clobber).
Behavior:
- During reads and mutations, ref values are resolved to the referenced JSON and treated as if the subtree were inlined at that node.
- Writes that touch a mounted subtree update the referenced file, while the main state keeps the ref string at the mount point.
- All referenced JSON files must also obey the verbiage key rule (
^[A-Z]+(-[A-Z]+)*$for all object keys, recursively).
{
"ACTIVE-PROJECT": { "TITLE": null, "PROJECT-ID": null },
"GOALS": {},
"ITEMS": { "GLOBAL": { "META": {}, "CONTENT": {} }, "PROJECTS": [] }
}By default, the bin CLI stores state at:
workers/chatter/bin/state/state.json
Override with STATE_PATH / STATE_LOCK_PATH if you want a different state file.
GOALS is an object keyed by goal key (a verbiage key). Each goal:
{
"TITLE": "<GOAL-KEY>",
"SUMMARY": "string",
"STATUS": "string",
"NOTES": ["string"],
"SUB-GOALS": {}
}SUB-GOALS is an object keyed by sub-goal key (a verbiage key). Each sub-goal:
{
"TITLE": "<SUB-GOAL-KEY>",
"SUMMARY": "string",
"STATUS": "string",
"NOTES": ["string"],
"EVENTS": [
{ "ID": "string|null", "TYPE": "string|null", "BODY": "string|null", "SEEN": false, "CREATED-AT": "string|null" }
],
"REQUEST-NOTES": ["string"],
"IN-FLIGHT": false,
"LAST-REQUEST": "string|null",
"LAST-SEEN-IDX": -1
}Item storage is a verbiage-keyed tree under three scopes:
- Global:
ITEMS.GLOBAL.{META|CONTENT} - Per project:
ITEMS.PROJECTS[](array of objects keyed byPROJECT-IDvalue) →ITEMS.{META|CONTENT} - Per chat:
ITEMS.PROJECTS[].CHATS[](array of objects keyed byCHAT-IDvalue) →ITEMS.{META|CONTENT}
Items are addressed by a slash- or dot-delimited verbiage path (e.g. ALPHA/BETA/GAMMA or alpha.beta.gamma). Values are stored directly at the leaf, which allows deep mutation by setting a deeper path later (e.g. set ALPHA/BETA to an object, then set ALPHA/BETA/INNER/LEAF).
If the value is JSON (object/array), all nested object keys are recursively normalized and validated as verbiage keys. Duplicates after normalization are rejected.
- Locking: all state mutations use
flockonSTATE_LOCK_PATH; writes are atomic and validated; no network under lock. EVENTSordering is append-only;LAST-SEEN-IDXtracks the highest seen index.- State ops (
chat state apply/reset) validate that all keys remain verbiage keys.
chat create goal/requestnormalizes goal/sub-goal titles to verbiage keys before storing.chat latestfinds the first unseen event across sub-goals, marks itSEEN=true, bumpsLAST-SEEN-IDX, and emits a human briefing. When none remain, it emits a ready/thinking roll-up.- Items:
project chat set/get/delete itemoperates at global/project/chat scope and uses the same verbiage normalization rules for paths and JSON object keys. chat state dumpfetches/browser/state-snapshotand stores it as a JSON string atITEMS/GLOBAL/META/MCP/STATE-SNAPSHOT(so it doesn't break verbiage-key validation).
- 2: invalid verbiage key/path (bad input).
- 3: invalid state/schema or domain errors (missing/duplicate goals/sub-goals; item not found; non-container intermediate during deep set).
- 4: inflight guard when a sub-goal already has a request in flight.
- 5: lock failure.
- 7: jq failure during apply/validation.