Skip to content

How It Works

Daniel Boles edited this page Nov 6, 2026 · 1 revision

How It Works

rosetta rests on one idea: a prompt's meaning lives in a small structured record, and the packet a model reads and the document a person reads are two renderings of that record. Because either rendering can be edited directly, the tool cannot trust a timestamp or a diff; it keeps a lock file with the SHA-256 hash of each rendering as it stood at the last successful sync, and it decides everything from a comparison with those two hashes.

The files

For an artifact called <name>, a directory holds four files that the tool manages, and a fifth that belongs to the user.

File Role Who writes it
<name>.fields.json The canonical record: a schema_ver and a fields object The user at the start; sync afterward
<name>.cpn The compact packet: SCHEMA_VER= first, then KEY=VALUE lines in sorted order, LF endings, one trailing newline Sync
<name>.md The human view: a generated block, then a hand-written notes region Sync for the block; the user for the notes
<name>.rosetta.lock The SHA-256 hashes of the .md and .cpn at the last sync Sync
<name>.schema.json A JSON Schema for validation The user

The Markdown block carries three things: a ROSETTA:FIELDS comment holding the fields as JSON, a ROSETTA:SCHEMA_VER comment, and one bullet per field. The comment is what sync reads when the Markdown changes, so the bullets exist for the human reader and the comment exists for the machine.

The sync decision

flowchart TD
    A["rosetta sync name"] --> B{"Lock file holds hashes"}
    B -- "No" --> C["bootstrap: write .cpn and .md from fields.json, write lock"]
    B -- "Yes" --> D{"Views that differ from the lock"}
    D -- "Both" --> E["CONFLICT: list differing keys, exit 1, write nothing"]
    D -- "Packet only" --> F["machine-to-human: parse packet, save fields.json, regenerate .md, keep notes"]
    D -- "Markdown only" --> G["human-to-machine: read FIELDS comment, save fields.json, regenerate .cpn"]
    D -- "Neither" --> H["no-op"]
Loading

The fields file is read at the start of every run and written during the two one-way paths, yet it takes no part in the decision. A change to fields.json alone therefore matches the "Neither" branch, and Limits and Next Steps treats that as the principal limit.

The main parts

Module Role
fields.py FieldsStore: load and save the JSON record with sorted keys and LF endings
cpn.py serialize_packet and parse_packet; floats are formatted to two decimals, and every parsed value is a string
human_doc.py Render the Markdown view; extract the fields comment, the schema comment, and the notes; raise MalformedRosettaDoc when a marker is missing
hashing.py and lockfile.py SHA-256 of a text, and the two-hash lock file
sync.py The decision above, plus SyncConflict, which carries the sorted list of differing keys
schema.py Draft 7 validation, with numeric strings coerced to the type the schema declares
loader.py load_prompt: serve the packet if it parses and validates, otherwise the Markdown as a full replacement, otherwise raise PacketUnavailable
cli.py sync, compile (an alias), validate, and expand

One edit, followed through

The example artifact rosetta_build holds three fields: CONFLICT_POLICY, DECISION_COUNT, and FIELD_VALUE_TYPES. Its packet begins SCHEMA_VER=1.0 and contains the line DECISION_COUNT=3.

  1. A user changes that line to DECISION_COUNT=4 and runs rosetta sync rosetta_build --dir <folder>.
  2. The lock file holds hashes for both views. The packet's hash no longer matches, and the Markdown's hash still does, so the branch is "Packet only".
  3. parse_packet reads the packet and returns the schema version and a fields dictionary in which every value is a string, so DECISION_COUNT is now "4".
  4. The fields store is saved with that dictionary, which is why rosetta_build.fields.json changes from the integer 3 to the string "4".
  5. extract_notes lifts the hand-written notes out of the existing Markdown, render_human_doc rebuilds the generated block from the new fields, and the notes go back in unchanged. A comparison of the Markdown before and after shows two changes, the ROSETTA:FIELDS comment and the DECISION_COUNT bullet, plus two blank lines around the notes region that the renderer normalizes; the notes text itself is identical.
  6. The lock is rewritten with the hash of the new Markdown and the hash of the packet as the user left it, and the command prints sync: machine-to-human.

rosetta validate then reads the fields file, finds "4" where the schema expects an integer, coerces it, checks the minimum of 0, and prints valid. Every step above was reproduced from the command line for this wiki.

What the runtime loader adds

The loader is the reason the Markdown exists as more than documentation. A consumer calls load_prompt(name, directory, schema); the packet is returned verbatim when it parses and passes the schema, and the Markdown is returned in its place when the packet is missing, malformed, or invalid. The Markdown is never appended to the packet. The tests cover four cases: a valid packet, a missing packet, a packet that fails the schema, and both files missing, which raises PacketUnavailable. A packet that does not parse, for example one without a SCHEMA_VER line, takes the same fallback in the code, although no test pins that case.

Clone this wiki locally