返回 CodeWhale
README.md
根目录 / pet / README.md
1 # Codewhale: a whale living in code
2
3 The current live experience is [one durable pet with attached views](SHARED.md):
4 Ratatui Watch/full habitat, browser, native companion and mobile Shared modes.
5 That guide contains build/run commands, source selection and the ownership
6 contract. The standalone demos and file studies described below stay isolated.
7
8
9 The dots are Codewhale's material. The whale is its recognizable home form;
10 real activity can reorganize that material into a living expression of the work.
11 This is an evolving audiovisual instrument, not a mascot that asks for attention.
12
13 The current implementation has a persistent 980-particle world, thirteen event
14 categories, deterministic audio, replay and checkpoints. Version 2 reorganizes
15 the same particles into knots for reasoning, woven strands for code, branches for
16 filesystem activity, scanning layers for browsing, and circulating paths for
17 network traffic. Human input opens a junction in the field. It does not steer
18 the creature toward its owner. The whale re-forms as activity settles.
19 These are authored expressions of measured activity, not generated pictures of
20 arbitrary task content. Missing telemetry stays visibly unknown.
21
22 ## Build from this repository
23
24 Requires Node 22.13 or later and Python 3 for the local static server.
25 No sibling repository, investor folder, credentials or provider call is needed.
26
27 ```sh
28 npm --prefix pet ci --ignore-scripts
29 npm --prefix pet run check
30 npm --prefix pet start
31 ```
32
33 Open <http://127.0.0.1:4632/pet.html>. Wild is a simulated creature; Event demo
34 is synthetic telemetry. Import trace / tape accepts event-v1, OTLP, existing
35 Codewhale session/Runtime journals and saved pet recordings. Sound requires an
36 explicit gesture. Still preserves a static semantic pose. Follow local tape
37 uses the browser's File System Access API; other browsers support import/export.
38
39 ```sh
40 # Regenerate embedded QuickJS and Apple bundles from the same source.
41 npm --prefix pet run sync
42 # Full product terminal; use /pet and /pet export.
43 cargo build --locked -p codewhale-tui --bin codewhale-tui
44 # Small standalone braille renderer, without the full product link.
45 cargo fetch --locked --manifest-path pet/tui/Cargo.toml
46 cd pet
47 ./verify.sh --no-swift
48 ```
49
50 `./verify.sh` without the flag additionally requires Swift and compares all
51 three ports. The script fails for a missing tool or failed build; it does not
52 silently call an omitted platform verified. See [QA.md](QA.md) for native builds.
53
54 The [Android application](android/README.md) builds with its Gradle wrapper and
55 JDK 17. Compose, native audio, checkpoint import/export and lifecycle behavior
56 are exercised on an Android 15 emulator; CI uploads the debug APK and test reports.
57
58 In the full terminal, `/pet sound on` enables the shared score and
59 `/pet sound off` mutes it. Sound starts off each time the application
60 opens. Install FFmpeg with `ffplay` on PATH to use this optional output; Watch
61 and recording work without it. The terminal streams the core's stereo 48 kHz
62 PCM to one player process. Hiding Watch, opening a modal, quiet mode, or stale
63 telemetry presentation suspends output. Reopening starts at the current clock,
64 without playing the intervening history. Player failure mutes sound and reports
65 a warning while the world continues. `/pet sound` shows its status.
66
67 ## One source of meaning
68
69 `src/core/pet-telemetry.ts` derives 400 ms buckets from normalized Whalesong
70 event-v1. Measured span occupancy selects the channel; onset counts, repeat
71 density, error receipts, human requests and agent identities carry other facts.
72 Container spans are excluded. Open-ended spans without observation coverage,
73 disconnects and missing intervals are unknown, not successful idle time.
74
75 `pet-world.ts` advances a 30 Hz creature clock and named seeded random streams.
76 It journals accepted telemetry, interactions, behaviors and persistent pod slots.
77 `pet-audio.ts` schedules voices from that same clock. Noise uses absolute sample
78 positions, so buffer partitioning cannot change the score. Audio mixing is a
79 host concern. `pet-native.ts` exposes this exact core to QuickJS/JavaScriptCore.
80 The TUI, Apple and Android hosts do not carry their own event bucketers or score schedulers.
81 Apple copies validated Float32 PCM channels directly from JavaScriptCore into
82 native buffers; it does not serialize sample arrays as JSON. AVAudioEngine
83 follows the world clock, rebases presentation after a stall, and discards stale
84 voices after a long gap. Device or rendering failures mute sound and report a
85 message while the world, persistence and export continue.
86
87 The Rust particle implementation lives in the product's
88 `crates/tui/src/tui/ambient_life/pet_sim.rs`; this package's runner imports it.
89 Swift and Kotlin particle ports must match its conformance digests. Generated
90 native bundles are committed so the product Rust build needs no Node compiler.
91 Run `npm run sync` after changing core source; the generated-byte check in CI
92 rejects a stale bundle. Local Whalesong consumers use aliases to these same
93 canonical files, not separately maintained source copies.
94
95 The original Whalesong importer, signal model, schema and browser storage code
96 are included because they are actual dependencies of the pet. Their original
97 Apache-2.0 [license](LICENSE) and [notice](NOTICE) are retained. Rust files imported
98 from the product retain that repository's license.
99
100 ## Live recording
101
102 The adapter only reads the existing Runtime journal endpoint
103 `GET /v1/threads/{id}/events`. It never starts a turn.
104
105 ```sh
106 cd pet
107 node scripts/pet.mjs --runtime=http://127.0.0.1:7878 --thread=THREAD_ID --output=pet.jsonl
108 node scripts/pet.mjs --input=trace.jsonl --output=other.pet.jsonl --watch
109 # Restart an existing live recording at the same path:
110 node scripts/pet.mjs --runtime=http://127.0.0.1:7878 --thread=THREAD_ID --output=pet.jsonl --resume
111 node scripts/pet.mjs --demo --output=demo.pet.jsonl
112 ```
113
114 Choose an existing thread and an unused output path, or use `--resume` to restart
115 a stopped live recorder at its existing path. Optional authentication
116 comes from `CODEWHALE_RUNTIME_TOKEN`; tokens are rejected in URLs. Only plain
117 HTTP loopback IP origins are accepted. Redirects, invalid envelopes and cursor
118 holes are rejected; reconnects resume from the last accepted Runtime cursor.
119 The recorder requests the Runtime stream's opt-in replay-progress capability.
120 It remains unknown until durable replay and the queued live tail have drained;
121 receiving the first historical event does not make it current. Broadcast-lag
122 recovery returns the stream to replaying. Older Runtime/SDK combinations without
123 this capability stop input explicitly and leave the recording unobserved; use
124 the Runtime built from this source alongside the recorder.
125 The recorder seals the preceding observation interval against a fixed clock.
126 It retains request lifetimes and counts a delayed error once at receipt time.
127 Raw prompts, arguments, results and tokens do not enter the pet recording.
128 Live recording continues in segments. At 216,000 buckets (24 hours) or 64 MiB,
129 the recorder syncs the completed file, preserves it as
130 `OUTPUT.segment-000001.jsonl` (then `000002`, etc.), and atomically replaces the
131 same live pathname. Each segment starts at sequence zero and replays independently.
132 Use `--segment-buckets=N` to rotate sooner. Followers establish a new baseline
133 after replacement, then accept subsequent appends as current observations.
134
135 The live importer retains unfinished lifetimes and 16 seconds of completed
136 events for the bucketer's recurrence window. It removes raw payloads immediately;
137 250,000 events and 64 MiB bound retained metadata, not total session history.
138 Completed output segments remain on disk, so disk use grows with recorded history.
139 Rotation requires same-directory hard links and atomic replacement. Unsupported
140 storage, an archive-name collision or an external replacement stops recording
141 without overwriting the existing files. With `--resume`, the recorder validates
142 the previous complete tape, preserves its exact bytes in the next numbered
143 archive, and starts a new segment at the same live path. The first bucket is
144 unknown; fresh source observations follow. It never invents events or estimates
145 the duration of an outage from file timestamps. The companion's separately saved
146 habitat preserves its particles and clock across attachment.
147
148 A private, empty `OUTPUT.writer-lock` sidecar uses Node's built-in SQLite OS lock
149 to exclude simultaneous recorders. Keep this file in place; its lock is released
150 on close or process death without deleting a stale PID file. It contains no
151 events. Use local storage with working OS locks, hard links and atomic rename.
152 Malformed, incomplete, oversized or non-file previous tapes are preserved and
153 rejected; use a new output path while retaining the original for recovery.
154 `--resume` applies only to live recording, and can also create an unused path.
155
156 The thin wire is JSONL, one flat version-1 `PetBucket` per line: PetState plus
157 `sequence`, `simTimeMs`, `durationMs`, thirteen-element `onsets` and `activeMs`,
158 `errors`, `agentIds` and `waiting`. Sequence starts at zero in 400 ms steps.
159 Saved replay JSON contains this accepted tape and the interaction journal;
160 a versioned checkpoint also contains particle, random-stream and score cursors.
161 Recordings also store `expressionVersion`: new worlds use version 2; recordings
162 without this field retain the original version 1 particle and behavior rules.
163 Checkpoints must agree with the recording's expression version. Unsupported or
164 mismatched versions are rejected before changing the current world. This keeps
165 old saved habitats replayable while letting new worlds change their visual form.
166 The older TSV is a particle conformance tape and cannot preserve audio onsets.
167
168 macOS watches `~/.codewhale/pet-state`. iOS watches `pet-state` in Documents.
169 Android uses More → Follow file study to select a seekable device document.
170 The browser's Follow local tape uses a user-granted File System Access handle.
171 All three file readers use the same shared live cursor: the first complete packet
172 establishes a baseline, and only an advancing sequence becomes an observation.
173 Duplicate input, a restarted sequence, or bytes read during suspension cannot
174 replay an old onset or human request. Missing/invalid input expires to unknown;
175 resuming advances beyond already accepted input without replaying its sound.
176 Apple watches appends and directory replacement. Android reads a bounded 256 KiB
177 tail on an IO worker, closes it on pause/background, and discards delayed delivery.
178 The file must be updated by a producer; selecting a completed tape does not make
179 it live. Use Import to replay that tape. Device files are not automatically synced
180 from the desktop recorder.
181 The current live chain has been exercised with typed synthetic Engine events
182 through the actual Runtime journal/SSE endpoint, recorder process and Apple
183 file watcher/host. The world receives a fresh human request and clears it after
184 its answer; prompt, question and answer text stay out of the recording. This
185 uses the existing mock Engine handle without calling a provider. The older
186 read-only Runtime 0.9.13 receipt predates the required progress capability and
187 does not establish current compatibility.
188
189 ## Persistence and current limits
190
191 The standalone browser commits checkpoint and recording together with an optimistic
192 IndexedDB revision. A saved live source reopens as Replay until explicitly
193 reattached. Legacy TUI `artifacts/pet/habitat.json` files remain recoverable; current Watch attaches to the companion.
194 Apple hosts keep source-specific files in Application Support/CodewhalePet.
195 Android keeps separate wild/demo/recording/live habitats in private app storage.
196 Native writes are private and atomic, use a writer lock and content revision,
197 and preserve corrupt files or external edits. Recovery is visible in the UI.
198
199 Modern checkpoints hydrate without replaying historical simulation. Live resume
200 starts unknown and drops old human requests. Apple legacy wild preferences
201 migrate only after a successful checkpoint save. Native autosave is every five
202 seconds, so a crash may lose work since the last successful save.
203
204 New worlds use version 2 recordings with an exact starting checkpoint and
205 absolute telemetry sequences. After 1,024 consumed buckets or 4,096 applied
206 inputs, the host saves completed history as an immutable segment before replacing
207 the active habitat. Only then does the running world retire that history. Its
208 particles, random streams and score continue without a reset. Gaps remain unknown;
209 future imported events stay in the active segment. Version 1 imports still work.
210
211 Earlier recordings opens saved segments in the browser and exports them on Apple
212 and Android. TUI segments are JSON files beside `habitat.json` in the session's
213 `artifacts/pet` directory. Each segment replays independently from its starting
214 checkpoint; seeking cannot precede that point. Browser source changes archive
215 the entire outgoing recording, including unplayed imported events. Archived files
216 are retained, so disk use grows with recorded history even though active history
217 is bounded.
218
219 Native autosaves and native imports are limited to 8 MiB; the QuickJS worker
220 has a 64 MiB memory limit. All four hosts export recordings in chunks, including
221 the exact checkpoint, with a 64 MiB file limit. Files over 8 MiB can be recovered
222 in the browser. Android finishes the export in a private staging file before
223 opening the user-selected destination. Apple source changes keep the current
224 visit when saving fails; leaving without saving requires an explicit choice.
225
226 A 30-hour synthetic Still run of the shared core rotated 263 segments and kept
227 the active file below 0.45 MB, with exact checkpoint continuation after every
228 rotation. Apple and Android separately exercise archive publication, failed saves
229 and continued execution in their actual embedded engines. This is not 30 hours
230 of animated native-device or power testing. Current platform builds, replay,
231 live file delivery and measured audio output have separate receipts in [QA.md](QA.md).
232 Automatic desktop-to-phone transport is not included: mobile hosts consume a
233 local file using the shared contract. Physical-phone listening/battery quality
234 and current macOS popover inspection have not been established. The source is
235 available as a development build; this branch has not been released.
236
236 lines MARKDOWN