ZCM
Playbook Studio
Sign in with your Studycat Google account to continue.
{{ signInError }}
{{ crumb }}
{{ pageTitle }}
Serving by app version
newest published, non-halted playbook whose minAppVersion ≤ the device
{{ startDraftCta }}
Continue draft {{ openDraftVersion }}
Each playbook is a floor with no maximum. Hash marks the region a newer playbook already covers. Click a version on the left to view or edit.
{{ r.version }}
{{ r.actionLabel }}
{{ r.bandLabel }}
App version →
{{ t.v }}
{{ edEyebrow }} Playbook {{ edVersion }} {{ edStatusLabel }} based on live {{ edBasedOn }}
{{ edSubtitle }}
Unsigned draft {{ edKeyId }}
Publish playbook
Go to draft {{ openDraftVersion }}
{{ startDraftCta }}
Target · minimum app version
app {{ targetVersion }}
{{ targetNote }} · released {{ targetReleased }}. Only hooks and metadata shipped by this version are guaranteed on every device — raise the target for newer capabilities, lower it to reach more installs.
{{ capHookCount }} hooks
{{ capStateCount }} state fields
{{ capEventCount }} events
{{ m.tagLabel }} {{ m.id }} {{ m.type }} {{ m.addedV }}
No metadata field matches — try another term.
{{ metaMatch }} matching · showing up to 40 {{ nextVersion }} adds {{ nextAddH }} hooks · {{ nextAddM }} fields
App hooks · engineer-owned
{{ activeHookId }}
Ordered first-match — the first matching directive wins, one outcome per hook.
{{ d.priority }}
{{ d.cohortName }} {{ d.statusLabel }}
{{ d.modeLabel }}
{{ d.warnText }}
No directives on this hook
The hook fires and the app continues as normal.

Cohorts

Defined with engineer-curated patterns. Operators tune parameters freely.
{{ c.name }}
AND{{ r }}
No rules — matches every user.
{{ c.usedCount }} {{ c.usedText }}

Pages

Each page carries its own verb and behavior. Authored and uploaded here, then paired to cohorts in the editor.
{{ c.usageLabel }}
{{ c.name }}
Updated {{ c.updatedAt }}
Simulated user
Resolve a hook against {{ previewVersion }} on an app {{ previewTarget }}+ device.
Signals this hook reads
{{ s }}
{{ hookDirCount }} directive(s) here. Greyed-out fields below don't affect this hook.
No directives on this hook — nothing to match. The runtime returns no-op.
Resolving against pasted app meta
Resolve hook
resolve(meta, "{{ pv.hook }}", ctx)
Resolution trace
{{ t.cohortName }}
{{ t.detail }}
{{ t.tag }}
Directive returned
{{ resultJson }}
Set up a user and hit Resolve
The Runtime evaluates directives in order and returns one outcome.
On device
Every change is recorded — who, when, what. Built on the internal-admin chassis with SSO.
{{ a.action }} · {{ a.target }}
{{ a.detail }}
{{ a.user }}
{{ a.ts }}
Directive · {{ dd.hook }}
{{ dd.title }}
{{ dd.cohortWarnText }}
50/50 split · stable per user via hash(user_id, experiment_id)
The Matchmaker picks the best page for this user at the hook.
{{ statusHelp }}
Save directive
Page
{{ cr.title }}
{{ cr.usageNote }}
Save page
Cohort
{{ cd.title }}
PATTERN
{{ o.label }}
No match
{{ cd.ruleCount }} {{ cd.ruleCountText }}
Save cohort
Compiled Playbook · {{ jsonVersion }}
signed
{{ playbookJson }}
Publish {{ publishVersion }}
Sign, version, and roll out to the base.
Changes vs {{ liveVersion }}
{{ c.sign }} {{ c.text }}
Signed in the cloud with the current rotatable signing key, itself anchored to the root key embedded in the app. The key id is recorded against the version once signing succeeds.
Publish failed — nothing was published.
{{ publishError }}
Takes effect at each user's next qualifying fetch.
{{ publishCta }}
Nothing to publish
{{ publishCta }}
Import app meta
Paste a real meta payload — the hook resolves against the full object, not just the fields above.
meta JSON
{{ metaError }}
Recognised keys: user_id, state, counts, days_since, flags. Extra keys are kept so cohort rules can read them.
Nothing leaves this screen — used only for this simulation.
Load meta
{{ toast }}