Skip to content

Make the skills work on cost-optimized models and in Cursor - #33

Merged
franco-zalamena-iterable merged 16 commits into
mainfrom
fix/cursor-reliability
Oct 22, 2026
Merged

franco-zalamena-iterable merged 16 commits into
mainfrom
fix/cursor-reliability

Conversation

@franco-zalamena-iterable

Copy link
Copy Markdown
Contributor

Summary

A Cursor trial on a bare React Native app, using Cursor's cost-optimized auto model, never provisioned anything. The agent read the skill's "Preflight — STOP" table but never ran bin/agent or opened iterable-provision. It wrote the Android and iOS code at once, and stubbed the Mobile key with a .example file. Cursor has no skill-invocation tool, so "route into iterable-provision" is only prose there, and a skimming model skips it.

This PR makes the order mechanical, so a cheap model gets it right:

  • "Start here" at the top of each integration skill (React Native, Android, iOS):
    • find <root> from the real path, resolving symlinks;
    • run the local preflight before asking or editing anything;
    • follow its next, which names the exact file to open and the commands to run;
    • never write a placeholder key or google-services.json;
    • React Native does Android first.
  • bin/agent preflight (local files only, with no network and no workspace created) reports what's present, missing or a placeholder. It returns next: provision | integrate | verify | done. iOS uses the existing local ios-provision status.
  • Step 0 asks whether the prerequisites exist. The recommended answer, "Not yet — set them up", starts provisioning.

It also carries the skill-text fixes found by the repo audit, which a Cursor run depends on:

  • Hand-back point: provisioning hands back on install_app (or run_app), not done, which only comes after a push arrives.
  • React Native key file: it's delivered during the Android phase, through ios-provision import-from-android.
  • Symlinks: they're resolved before walking up to bin/.
  • The provisioning and verifier tables: they now match what the programs route.
  • Contradictions and internal wording: cleaned up across the skills.

It also carries the README update:

  • the iOS and React Native flows, the account roles and host requirements;
  • the corrected update command and Android JWT limitation;
  • Codex updates and uninstalling;
  • the Cursor plugin install (Customize → + Add → From GitHub Repository);
  • the confidentiality notice removed.

Version 26.10.5-beta.

How it was tested

  • New suite: tests/agent-preflight.sh (12 checks). It covers:
    • fresh, proven and placed states;
    • placeholder keys and .example files;
    • no key value in the output;
    • no workspace written;
    • gcloud, curl, adb and firebase never called.
  • Existing suites, run locally: agent-questions, agent-next-action, workspace-writes, no-raw-http, text-surface, no-bare-commands, pitfalls-agree, decision-docs and plugin-manifests all pass. CI runs the full suite.
  • On the trial app: preflight on the reset Jellify app returns provision, and names iterable-provision/SKILL.md and bin/agent question opening.

🤖 Generated with Claude Code

The README still described an Android-only flow in places, used an update
command that has no in-session form, and said JWT keys work for core
verification on Android, where the key check refuses them. It now covers the
iOS setup and host requirements, the React Native order and Release build, the
account roles each provider needs, proof side effects, Codex updates, and
uninstalling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cursor imports skills from a repository as a plugin (Customize, From GitHub
Repository), which also brings the scripts and the Context7 MCP server.
Linking skill directories stays as a fallback without the MCP server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skills are read by outside developers and their agents. Internal Jira
keys mean nothing to them, and "in our trial" / "proven live" anecdotes read
as war stories rather than guidance. Each passage now states the rule or the
observed behaviour directly, and the Android key-name example is neutral.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
next_action reports done only once a push has reached the device, which
cannot happen before the platform skill writes the integration. After the
Google and Iterable gates pass, the next kind is install_app (or run_app if
the app is already installed), so a skill waiting for done never handed
over. All three skills now name the state the tool actually reports, and
the artifact that is on disk by then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The React Native skill promised that provisioning writes the key file the
JavaScript app reads, but only the iOS program writes it, and Android runs
first: the Android program keeps the key in .iterable/.env, which the app
never reads, so a bare RN or Expo app had no key until the iOS phase, or at
all when iOS was out of scope.

ios-provision import-from-android already does exactly this. Its state is
the first one the iOS program reaches when an Android setup exists, before
any Apple step or Xcode check, and it writes .iterable/rn/iterable.local.ts
or .env.local at 0600 without printing the key. The skill now runs it in the
Android phase, guards the Expo .gitignore first (the import skips .env.local
silently when git would commit it), and checks the file without reading the
key. Reusing the one writer avoids a second copy of the file format in the
Android program. The iOS phase then gets carry_scope for the Step 0 answers,
which ios.md and INTENDED-FLOW now describe; INTENDED-FLOW also stops
claiming both platforms share one scope record, since Android records none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reference presented ios-send target as the way to send user-targeted
proof, but standard proof sends through ios-prove --confirm, the one actor
the verifier names in next.command. Agents following the reference on a
standard run were reaching for the instrumented sender.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cursor installs can link a skill directory into ~/.cursor/skills. Walking
up from the link's path never reaches the plugin's bin/, so the skill
concluded the install was incomplete. Every skill that finds bin/ by
walking up now says to start from the real path, in the same sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Several rows described routing the code does not do. The Iterable step
screens carry the step in prompt (questions.sh builds it from iterable-keys
--prompt) and use context only for the relay instruction, yet two passages
told the agent the step was in context, which invites cutting prompt down to
its question line. next_action reports investigate for a red token,
registration, or delivery gate, and neither kind table had a row for it.
ios-verify routes a standard physical-iPhone run through ios-prove with a
read-back code; ios-deliver is reached only in instrumented runs. The
opening-question section is also labelled Android, since the iOS path does
not start there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The identity relaunch is the identity screen's opt-in read-identity
  option, not something the verifier does; INTENDED-FLOW's "never
  relaunches" now says the same.
- React Native binds the Release build through the App build screen, or
  restart --confirm --app-path for an existing run, instead of telling the
  agent to append --app-path by hand.
- The React Native pitfall index and its Expo-only note now agree with the
  headings and with #3, where both workflows request at runtime.
- The native iOS "ask in context" rule notes that bare React Native asks at
  launch in AppDelegate, which is the intended RN behaviour.
- "Not in this skill" sends dashboard questions to the shipped doc first,
  as Preflight already does.
- Xcode registers the App ID only for a device build's profile, so a
  Simulator-only app usually lacks it; the Android proof runs on a device or
  an emulator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An integration skill needs to know, before asking or editing anything,
whether the prerequisites exist. preflight reads only local files (the
google-services.json copies, key presence in .iterable/.env, the React
Native key file, the last ladder record), writes nothing, prints no key
value, and flags placeholder or .example files as missing. Its next is
provision, integrate, verify or done, with the file to open and the
exact commands to run, so a weak model has no order to infer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Cursor trial on a cost-optimized model skimmed the React Native skill,
never ran bin/agent, never opened iterable-provision, wrote both
platforms at once and a placeholder key file. Each integration skill now
starts with a few numbered commands: find <root>, run the local
preflight (ios-provision status on iOS), open iterable-provision by path
when prerequisites are missing, never write a placeholder, and on React
Native finish Android before any iOS edit. Step 0 asks whether the
prerequisites exist, recommending "Not yet — set them up".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	.claude-plugin/plugin.json
#	.cursor-plugin/plugin.json
ASK.md was written from the first red gate only, so a pending Iterable
step (no server-side key yet) before a red install gate was skipped: the
file said "waiting on you at App installed with the SDK" and the agent
went on to write code. It now names the step next_action picks, the same
one the banner and the agent path show.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ASK.md the agent followed in the Cursor run was left over from an
earlier run. bin/gates writes it only when the first red step is the
developer's; that run's first red step was the tool's (the FCM role), so
the old file stayed and still named a later step. Rerouting its content
through next_action did not touch that, and gave tool-owned steps "only you
can clear" wording, so this goes back to the original content and deletes
the file at the start of each run instead.

This reverts commit 7a617ce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@franco-zalamena-iterable
franco-zalamena-iterable merged commit 24986f9 into main Oct 22, 2026
2 checks passed
@franco-zalamena-iterable
franco-zalamena-iterable deleted the fix/cursor-reliability branch October 22, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant