Skip to content

Quickstart: compile an English pilot package ​

This walkthrough is for implementation collaborators who already have approved repository access. It proves the current English path, shows the recommended authoring order, and compiles a new package without treating compilation as publication or runtime installation.

阅读中文版

Prerequisites ​

Run commands from the repository root. The compiler requires Python 3.11+ and uv; the playable local application also requires Node.js 20.19+ and Docker. Use npm run setup if the repository dependencies have not yet been prepared.

1. Prove the compiler with the English canary ​

The repository's Orbital Garden Relay canary is deliberately synthetic and lives under test fixtures. Compile it with its fixture content root:

bash
uv run --project apps/api meet-u-compile-pilot \
  --content-root apps/api/tests/fixtures \
  --output-root /tmp/meet-u-orbital-bundles \
  --package-id orbital-garden-relay \
  --version 1

A successful result is JSON with "status":"succeeded", paths to the canonical IR and runtime-bundle content, and a content digest. It also says "activatable":false; that is expected.

Verify that the existing content-addressed output exactly matches a fresh compile:

bash
uv run --project apps/api meet-u-compile-pilot \
  --content-root apps/api/tests/fixtures \
  --output-root /tmp/meet-u-orbital-bundles \
  --package-id orbital-garden-relay \
  --version 1 \
  --check

--check does not create the expected output for the first time. Run the ordinary compile first, keep the same output root, and then run --check.

2. Create the package directory ​

Production-tree source packages use this path:

text
content/creator-sources/my-pilot/v1/

Use a package ID made from lowercase letters, digits, and hyphens, beginning with a letter or digit. The path, compiler argument, and source-package.yaml identity must agree exactly:

yaml
package:
  id: my-pilot
  version: 1

Create all seven fixed YAML filenames listed in the technical package overview. The manifest's six module references are closed literals; the compiler does not accept alternate names or omit a module.

Use the v1 field reference for every field and nested type. The source models reject unknown fields, so do not infer field names from the broader proposal specification.

3. Author meaning before wiring IDs ​

Write a short Creator brief before filling YAML. Settle these questions:

  1. Who is the character, and what makes their choice recognizably theirs?
  2. Why can the remote user communicate with them without entering the world?
  3. What can the user ask, challenge, comfort, or influence—and what can they never directly do?
  4. What is the bounded dilemma, and which decisions remain faithful?
  5. What objective outcome follows each allowed decision?
  6. What does the character observe, choose to disclose, and later tell the user?
  7. What exact visual and Journal evidence makes the causal chain legible?

This brief is the human-created dramatic foundation. The compiler checks its typed expression; it does not invent missing drama.

4. Fill the seven files in dependency order ​

A. source-package.yaml ​

Declare the schema version, package identity, six fixed module references, at least one external provenance reference, and non-empty semantic_parity.preserves and semantic_parity.excludes lists.

This is the manifest shape for the example package:

yaml
schema_version: meet_u.creator_source_package.v1

package:
  id: my-pilot
  version: 1
  display_name: My Pilot
  ip_title: My Original IP
  default_locale: en-US
  primary_character_id: my_character
  arc_id: first_dilemma

modules:
  character: character.yaml
  relationship: relationship.yaml
  arc: arc.yaml
  dialogue: dialogue.yaml
  visual: visual.yaml
  acceptance: acceptance.yaml

provenance:
  - role: semantic_normalization_authority
    ref: creator-private://my-pilot/reviewed-brief-v1

semantic_parity:
  preserves:
    - "REPLACE: specific meaning retained from Creator material or an accepted decision"
  excludes:
    - "REPLACE: mechanics or historical behavior intentionally outside this source"

The manifest also names the primary character and arc IDs. Reuse those exact IDs in character.yaml, relationship.yaml, and arc.yaml.

Every REPLACE value above must be replaced before review. The example creator-private reference is only a placeholder for a durable, access-controlled source record; it does not define an intake storage scheme. Provenance must truthfully identify the source of the normalized meaning; it is not a box to check. The current role vocabulary is unusually narrow. If a new IP's source cannot honestly use one of the allowed roles, do not invent a reference or mislabel the source just to compile—record the contract gap first. See the provenance role boundary for the complete current list and limitation.

B. character.yaml ​

Define identity, values, goals, contradiction, boundaries, prohibited portrayals, decision tendencies, knowledge limits, disclosure posture, voice, and constructive refusal. Write these as portrayal constraints and dramatic meaning, not as instructions to obey the user.

Use constructive_refusal.style_anchor to calibrate genuine refusals. Author terminal CHAT_ONLY copy separately under dialogue.recovery so a generic realization failure does not sound like a judgment about the user.

C. relationship.yaml ​

Describe the user as a remote confidant and keep the fixed v1 channel flags false: the user has no physical presence; NPCs cannot receive, verify, or answer user messages; and the character cannot forward the raw message.

Choose a small, semantic influence_vocabulary, such as support, challenge, or respected boundary meanings appropriate to this character. These IDs are evidence categories, not keywords and not commands that select a decision.

Add the optional reciprocal promise or invented shared context only when the story genuinely needs it. Every extra semantic mechanism adds cross-file obligations.

D. arc.yaml ​

Author in this order:

  1. narrative time, world facts, locations, NPCs, and one narrative deadline;
  2. the current Arc Progression V1 phase and its initial character beliefs;
  3. character decisions, each with typed eligibility, qualitative influence fit, one typed action, and one outcome ID;
  4. one deterministic outcome for every decision; and
  5. exactly one character-owned return follow-up for every outcome, plus one dedicated follow-up per creator-fixed beat if the branch declares an optional progression.aftermath chain; a decision-bearing beat (one carrying decision_phase) authors no world_event or followup_id and claims no dedicated follow-up — its return uses the chosen outcome's return follow-up.

Although arc.progression is optional in the base source model, it is required by the only current CLI build target, local_owner_synthetic_preview. Its decision phases — the branch decision_phase plus any decision-bearing beats — must carry disjoint candidate sets that together cover every decision exactly once, and the branch phase uses the declared world deadline as its single horizon.

Write narrative_time.anchor_local_time and the deadline's narrative_local_time as ISO local times such as "05:20". Quote them so the YAML parser preserves text. If a reciprocal promise has a narrative due time, quote its ends_local_time the same way.

The terminal no_eligible_guidance.public_projection.text must include en-US for an English package. It may also contain zh-CN, but the rest of the package is not translated automatically.

E. dialogue.yaml ​

Write the exact Creator opening, guided ordinary-dialogue obligations, recovery declarations, one semantic-lock dialogue entry per arc follow-up, and exact Journal copy.

Keep opening.generated_reply_suggestions: false for the current pilot work. The schema can carry a boolean, but accepted product decisions leave broader suggested-reply enablement open; a compilable true value is not authorization to ship that interaction.

For an English package, both recovery.degraded_chat.locale and every recovery.chat_only[].locale must be en-US. Every fact ID in a must_not_disclose_fact_ids list must exist in the arc fact graph.

Across the CHAT_ONLY surfaces, cover the three required immediate recovery contexts exactly once: ordinary_no_effect, capability_boundary, and their combined set. Each surface carries its own exact_text; use separate ordinary and capability surfaces whenever those contexts require different meaning. Existing v1 packages may still use the legacy exact_text_ref: character.constructive_refusal.style_anchor; new packages should prefer explicit dialogue-owned text.

The Journal is exhaustive: provide exactly one statement for every influence kind, decision ID, and outcome ID. Statements describe the validated causal record; they must not credit the user with the character's action or the world result.

F. visual.yaml ​

Declare visual identity, one portrait asset, optional public discovery presentation, and at most one depiction per outcome — every depicted outcome must exist, and a text-only outcome (for example a decision-bearing beat's outcome) may omit its depiction. A package must include visual.discovery to enter the package-driven gallery even though the field remains optional for backward compatibility. Assets must already exist. Package-local paths begin with assets/; the only allowed external alternative is the same package/version's historical pilots/<package-id>/v<version>/assets/ namespace, written relative to the selected content root. For --content-root content, for example, write source_path: pilots/my-pilot/v1/assets/portrait.png; the corresponding repository file is under content/pilots/..., but content/ is not part of the YAML value.

visible_fact_ids may include only externally visible facts committed by that outcome. Put private or visually misleading facts in forbidden_fact_ids. Asset provenance is required authorial traceability; it is not asset approval.

The current compiler accepts .avif, .gif, .jpeg, .jpg, .png, .svg, and .webp for portraits and outcome assets. A discovery cover is static and accepts only .avif, .jpeg, .jpg, .png, or .webp. The suffix comparison is case-insensitive, and the emitted bundle path is derived from the asset ID and normalized suffix. See the gallery cover guide for the exact 3:4 crop, focal point, copy, and fact-boundary contract.

G. acceptance.yaml ​

Write meaning-level cases that distinguish useful user positions, expected influence kinds, allowed decision space, and forbidden effects. Add paraphrase ranges that should preserve meaning across different wording.

Never write quoted phrases as routes. Acceptance cases are evaluation evidence; they cannot directly choose stance, action, outcome, or reply.

5. Compile the package ​

For the example identity above:

bash
uv run --project apps/api meet-u-compile-pilot \
  --content-root content \
  --output-root /tmp/meet-u-my-pilot-bundles \
  --package-id my-pilot \
  --version 1

After it succeeds, rerun the same command with --check:

bash
uv run --project apps/api meet-u-compile-pilot \
  --content-root content \
  --output-root /tmp/meet-u-my-pilot-bundles \
  --package-id my-pilot \
  --version 1 \
  --check

The compiler reads the whole source and asset closure, validates cross-file meaning, lowers deterministic canonical IR, and emits content-addressed runtime bundle files. It does not call an LLM.

6. Read failures from the outside inward ​

Error familyWhat to check first
Invalid or duplicate YAMLIndentation, quoting, unique mapping keys, UTF-8 text, and whether the document root is a mapping
Semantic contract violationThe field path in the Pydantic error and the exact type/closed value in the field reference; unknown fields are rejected
Forbidden Creator source fieldRemove runtime, provider, prompt, approval, lifecycle, or raw-text routing configuration from Creator YAML
Package identity mismatchDirectory ID/version, CLI arguments, manifest package identity, primary character references, and arc ID
Unknown or inconsistent referenceTrace the ID across relationship, arc, dialogue, visual, and acceptance modules; do not fix it by inventing a second near-duplicate ID
Missing Arc Progression V1Add arc.progression, a world deadline, full decision coverage, and the default-locale no-eligible projection
Locale catalog or recovery mismatchUse exactly en-US or zh-CN; make every recovery locale equal package.default_locale
Incomplete or ambiguous CHAT_ONLY recoveryCover the immediate ordinary-no-effect, capability-boundary, and combined obligation sets exactly once across all chat_only surfaces
Missing or unsafe assetCheck file existence, case, package-local assets/ path, absence of symlinks or .., and that every depicted outcome exists with at most one depiction
Unsupported media suffixUse .avif, .gif, .jpeg, .jpg, .png, .svg, or .webp
Journal coverage mismatchProvide one and only one statement for every influence kind, decision, and outcome
--check bundle mismatchCompile once to that output root, keep the same source/compiler/policy inputs, and check that the expected digest directory still exists

Source values must be canonical: mapping keys are strings, floating-point numbers are forbidden, integers must be JavaScript-safe, and booleans should be YAML booleans rather than quoted strings. Declared paths cannot be absolute, escape their allowed root, contain symlinks, or collide after Unicode/case normalization.

7. Stop at the correct boundary ​

A green compile proves that one frozen source graph can be lowered under the current compiler and platform policy. It does not prove rights, Creator approval, asset approval, behavioral qualification, release eligibility, or activation. Continue with compilation and lifecycle before making any broader claim.

Creator-authored stories. Character-first experiences.