Skip to content

Latest commit

 

History

History
108 lines (84 loc) · 4.91 KB

File metadata and controls

108 lines (84 loc) · 4.91 KB

State Schema and Rules

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.

External references (sharded JSON)

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.

Convenience for the default layout

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.

Inline initialization

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).

Shape

{
  "ACTIVE-PROJECT": { "TITLE": null, "PROJECT-ID": null },
  "GOALS": {},
  "ITEMS": { "GLOBAL": { "META": {}, "CONTENT": {} }, "PROJECTS": [] }
}

Default state path

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

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
}

ITEMS

Item storage is a verbiage-keyed tree under three scopes:

  • Global: ITEMS.GLOBAL.{META|CONTENT}
  • Per project: ITEMS.PROJECTS[] (array of objects keyed by PROJECT-ID value) → ITEMS.{META|CONTENT}
  • Per chat: ITEMS.PROJECTS[].CHATS[] (array of objects keyed by CHAT-ID value) → 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.

Defaults and invariants

  • Locking: all state mutations use flock on STATE_LOCK_PATH; writes are atomic and validated; no network under lock.
  • EVENTS ordering is append-only; LAST-SEEN-IDX tracks the highest seen index.
  • State ops (chat state apply/reset) validate that all keys remain verbiage keys.

Behaviors

  • chat create goal/request normalizes goal/sub-goal titles to verbiage keys before storing.
  • chat latest finds the first unseen event across sub-goals, marks it SEEN=true, bumps LAST-SEEN-IDX, and emits a human briefing. When none remain, it emits a ready/thinking roll-up.
  • Items: project chat set/get/delete item operates at global/project/chat scope and uses the same verbiage normalization rules for paths and JSON object keys.
  • chat state dump fetches /browser/state-snapshot and stores it as a JSON string at ITEMS/GLOBAL/META/MCP/STATE-SNAPSHOT (so it doesn't break verbiage-key validation).

Exit codes (state-related)

  • 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.