an.ir.sync

Bidirectional sync between scene.md (Narrative Layer) and ir/scene.json (Scene Graph Layer).

The Markdown form is what humans edit. The JSON form is what the agent and verifiers operate on. They must round-trip cleanly.

Markdown convention (v0.1, kept simple — extended in P5):

# <title>

Optional prose intro (saved to meta.notes).

`yaml meta title: Park Bench duration: 45 fps: 30 `

## Shot s1 (cutout)

Optional prose direction for this shot.

```yaml shot duration: 15 camera:

move: push_in

```

`dialogue charlie: Did you ever wonder why we always meet here? maya: Because the pigeons trust us. `

A shot heading is ## Shot <id> (<style>). Fenced blocks attach to the nearest enclosing scope. Unknown blocks are preserved as options so agent extensions don’t get clobbered on round-trip.

class an.ir.sync.SyncResult(wrote_json: bool = False, wrote_md: bool = False, drift_warning: str | None = None)[source]

Outcome of a sync operation.

an.ir.sync.ir_to_markdown(scene: SceneIR) str[source]

Render a SceneIR back into the structured Markdown form.

>>> from an.ir.schema import SceneIR, Meta, Shot
>>> scene = SceneIR(meta=Meta(title="Demo", duration=5.0),
...                 timeline=[Shot(id="s1", style="cutout", duration=5.0)])
>>> md = ir_to_markdown(scene)
>>> "# Demo" in md
True
>>> "## Shot s1 (cutout)" in md
True
an.ir.sync.markdown_to_ir(md_text: str) SceneIR[source]

Parse the structured Markdown form of a scene into a SceneIR.

>>> md = '''# Demo
...
... ```yaml meta
... title: Demo
... duration: 5
... ```
...
... ## Shot s1 (cutout)
...
... ```yaml shot
... duration: 5
... ```
...
... ```dialogue
... charlie: hi
... ```
... '''
>>> scene = markdown_to_ir(md)
>>> scene.meta.title
'Demo'
>>> scene.timeline[0].id
's1'
>>> scene.timeline[0].dialogue[0].text
'hi'
an.ir.sync.sync(project_dir: str | Path) SyncResult[source]

Reconcile scene.md and ir/scene.json inside a project directory.

Strategy in v0.1: Markdown is the human SSOT; if both exist, the JSON is regenerated from the Markdown unless mtimes show JSON is newer (which the user is told never to do — but we warn instead of silently overwriting).