OPS: Native First Routing - Free search first, paid DeepAPI only when free tools fail

The actual documents the agents read and work from, shown exactly as they are on disk β€” not a summary. See the progress view instead Β· All projects

Plan PLAN.md

# PLAN β€” NATIVE-FIRST ROUTING: free search first, paid DeepAPI only when the free tool fails

Owner: Nick. Purpose: plan (this project's only record; RULE 51). Card: `ac-ai-builds-ops-native-first-routing-free-search-first-paid-`.

**πŸ”΄πŸ”΄ THIS IS THE ONLY PLANNING DOCUMENT FOR THIS PROJECT. Do not create a second plan, tracker, summary, or scratch state file β€” extend THIS file. Any status view is GENERATED from this plan; if a view disagrees with the plan, the plan wins.**

**NORTH STAR:** Nick, 2026-09-20: *"what do agents use deep api for that isnt needed to be done via deep api? we burn so much money there"* β€” every agent, on every Mac and account, uses the free tools (web search, page reads, the browser, GitHub) first and spends on DeepAPI only when the free tool cannot do the job, and if that ever slips it is caught the same day, not months later.
**FINISH LINE:** (1) a paid DeepAPI web search, page read or deep research typed by any Claude session is refused unless the agent names what the free tool failed to do, and the platforms only DeepAPI can reach still go through; (2) Codex, inside and outside the project, carries the native-first rule; (3) the vendor's "use DeepAPI for everything" instructions are replaced on every installed copy and stay replaced through the vendor's daily update; (4) a daily read of DeepAPI usage goes red on paid web searches or page reads the Muse research job did not make; (5) freshly started sessions (Claude outside the project, Claude inside, Codex outside, Codex inside, plus one dispatched helper) pick the free tool for an ordinary lookup; (6) every reachable Mac reads back green, and every unreachable one is written down as NOT DONE.

**Owner:** Nick Β· **Overseer:** this Opus session (plans, judges, signs off; safety-wall code stays on Anthropic per CORE Β§3) Β· **Design authority:** none β€” nothing rendered
> **STEP 0 β€” ARM THE LOOP, BEFORE ANYTHING ELSE.** Set a 5-minute loop. Every time it fires, answer
> these five in order and CORRECT any failure before doing anything else:
> 1. **NORTH STAR** β€” is what I am doing this minute moving this plan's North Star? If not, drop it.
> 2. **FAN-OUT** β€” declare the whole actual roster, dispatch useful ready work, and shed your own unnecessary processes. Coordinate through peers or the launching dispatcher; no numeric cap or load-wait rule applies.
> 3. **CHEAP** β€” are cheap models doing the building AND the per-step checking? If anything on
>    Anthropic or OpenAI is building or checking a step, move it down now (Β§M).
> 4. **STUCK** β€” for anything I have called blocked: name the input that does not exist yet, or the
>    three concrete things I tried. If I cannot, it is not blocked β€” drive through it now.
> 5. **NEXT** β€” did something just finish? Then the next step whose inputs exist starts THIS minute.
>    A finished step is never a place to stop, a report is never a reason to wait, and Nick being
>    away or asleep is the reason to keep going, not to pause.
> Then keep building. The loop never stops until the FINISH LINE is proven.

**Rule: a step starts the moment its named inputs exist, whatever its number. A step closes on ONE independent check by a different model. Nothing waits on Nick to test.**

## Already true (facts, not story)

- The scope was set by a triad on 30 Sep 2026: Skippy's recommendation 7 was cold-reviewed by Fable and by Astra separately, both said PROCEED WITH CHANGES, and this session broke the ties (cut "find Slack unaided" and prose-injection tests; a call-level gate is the only loud failure; fresh sessions judged by the tool actually used, not by reciting the rule; "permanent" dropped for "verified for these versions"). β€” evidence: `evidence/reviews/` beside this file (the brief, both reviews, every sign-off round); the tie-breaks are in the POSTMORTEM below.
- Codex started outside the project never sees RULE 61: `~/.codex/AGENTS.md` carries only the Rafter retirement and the ten-minute kill; `~/.codex3/AGENTS.md` still carries a retired Rafter block. β€” evidence: `cat ~/.codex/AGENTS.md ~/.codex3/AGENTS.md`, 30 Sep 2026.
- The vendor skill (installed at `~/.agents/skills/deepapi`, `~/.claude/skills/deepapi`, `~/.codex/skills/deepapi` on the Studio; absent on the Mac mini) says "use DeepAPI for all web search … instead of built-in" tools, maps "Open-web search" and "Read any webpage" to paid endpoints, and orders "5+ different, separate `/v1/search/web` API calls" per question. β€” evidence: `sed -n 3p ~/.agents/skills/deepapi/SKILL.md`; its "Picking the Right Endpoint" section.
- The vendor updater keeps an edited SKILL.md (a fingerprint mismatch is counted as a customisation and left alone) and restores only a missing or untouched one. β€” evidence: `~/.deepapi/update-skill.sh`, `is_official_skill` and `install_bundle`; `DEEPAPI_INSTALL_HOME` redirects it to a test home.
- Our own installer never resurrects the vendor skill: it reports a real folder it did not make as FOREIGN and leaves it. β€” evidence: `ZION/lib/install-skills.sh` lines 117–120.
- No hook anywhere looks at DeepAPI calls today. β€” evidence: `command grep -rl "deepapi" projects/ops/hooks .claude/settings.json` β†’ nothing, 30 Sep 2026.
- The Muse research job legitimately calls `/v1/search/web` and `/v1/scrape/website` every 10 minutes under the Hub's spend allowance (Nick, 30 Sep). β€” evidence: `projects/ops/skippy-jobs/lib/content-discovery/providers.mjs` lines 17–18; DeepAPI `/v1/usage`, 7 days to 30 Sep: 74 web searches, 9 page reads.
- The Slack person-identity gate is live for Claude in the workspace and has its own selftest; Codex has no Slack connector. β€” evidence: commits `b7ed8d7af1`, `06bef7442c`; `~/.codex/config.toml` MCP list.

## 0 Β· Gate Zero receipts (the plan may not exist without these)
- Failure Mode Registry loaded: 30 Sep 2026, `references/failure-registry.md`; entries this build is exposed to are named in Β§4.
- Canonical specs loaded: CODE (`projects/ops/agents/CODE-STANDARD.md`), QA (`projects/ops/HANDBACK-GATE-SPEC.md`); no design spec β€” nothing rendered.
- Ownership check: `projects/ops/artifacts/project-status/registry.json` has no DeepAPI or routing row (searched 30 Sep 2026); the Hub had no card (287 cards searched 30 Sep 2026 7 pm); this plan's card was opened the same evening.
- Expected inputs confirmed to exist: `~/.deepapi/update-skill.sh` (present), `~/.deepapi/env` (present), DeepAPI `/v1/usage` (200, free, 30 Sep), the Mac mini over ssh (reachable 30 Sep 7 pm), the 30-minute sync job `com.skippy.skills-cloud-sync` on Studio and mini (present).
- PLAN AUTHOR: Opus session of 30 Sep 2026 (the triad tie-breaker).
- COLD READER: none β€” SINGLE-AUTHOR, UNREVIEWED (the scope itself was cold-read twice, by Fable and Astra, before this plan).
- PROMPT-SPEC scan (P1–P7): "Slack API unaided" (P1, undefined) β†’ cut by the triad; "fail loudly" (P1) β†’ defined as a refused call naming the free tool; "every machine/account" (P4) β†’ Macs this session can reach by ssh, the rest recorded NOT DONE.

## 1 Β· Goal and definition of done
- **What we're building, one paragraph.** A guard that refuses a paid DeepAPI web search, page read, deep research, PDF read, GitHub scrape or browser run unless the command names what the free tool failed to do; the native-first rule written into every Codex instruction file and every installed copy of the vendor's DeepAPI skill, kept there by the 30-minute sync job every Mac already runs; the guard wired into every Claude session on the Mac, not only sessions in this workspace; a daily usage read that goes red on paid web searches or page reads the Muse job did not make; and fresh-session tests that prove a newly started agent actually picks the free tool.
- **HOW IT'S USED:** nobody touches it. Agents meet it when they reach for DeepAPI out of habit; Nick meets it only as a smaller DeepAPI bill and, if something slips, one red line the watchers pick up. Β· HOW WE KNOW: RULE 61's measured spend (90 days to 20 Sep: $16.37 of avoidable search and page calls).
- **WHAT IT LOOKS LIKE:** a refusal message in the agent's own session naming the free tool to use and the one-line override; a status line per Mac in the sync log; a HEARTBEAT row from the daily usage read. Β· HOW WE KNOW: the gate's selftest prints the refusal text.
- **WHERE IT LIVES:** `ZION/lib/check-deepapi-native-first.mjs` (the gate), `ZION/lib/native-first-sync.mjs` (keeps rules and wiring in place on each Mac), `ZION/lib/native-first/` (the rule text), `projects/ops/skippy-jobs/jobs/deepapi-watch.mjs` (the daily read); opened by nobody β€” Nick reads the card. Β· HOW WE KNOW: the sync job runs the cloud copy of `ZION/`, so `ZION/lib` reaches every Mac within 30 minutes of a push.
- **WHAT IT MUST DO:** the seven capabilities below, each an eval in Β§6. Β· HOW WE KNOW: each is RULE 61's own wording turned into a check.
  1. Refuse a Claude Bash command that calls DeepAPI `/v1/search/web`, `/v1/scrape/website`, `/v1/research/deep`, `/v1/scrape/deep`, `/v1/scrape/extract`, `/v1/scrape/pdf`, `/v1/scrape/github*` or `/v1/browser/act` without `NATIVE-FAILED: <reason>`; let the LinkedIn, X, Instagram, TikTok, Threads, Truth Social, Facebook, Amazon, Google Places, YouTube, Reddit, SEO, image, transcription, account and memory routes through; log every override.
  2. Put the native-first block into every `~/.codex*/AGENTS.md` except `~/.codex2` (Chantelle's account, off limits by Nick's ruling 2026-09-16).
  3. Rewrite every installed vendor DeepAPI SKILL.md so it states RULE 61 first and no longer orders paid search; refresh from the vendor's current copy once a day through a separate test home, so vendor endpoint changes still arrive.
  4. Wire the gate into the user-level Claude settings on each Mac, so sessions outside this workspace are covered.
  5. Read DeepAPI usage daily and go red on web searches or page reads beyond those the Muse job logged.
  6. Pass the fresh-session lookups on the free tool.
  7. Read back every reachable Mac; write unreachable ones as NOT DONE.
- **NOT in scope:** (a) changing the Muse research job's use of paid web search β€” Nick approved it with its own $10 allowance on 30 Sep; (b) blocking DeepAPI inside scheduled job code β€” the gate sees typed commands only, and the daily usage read is the net for jobs; (c) any Codex hook β€” Codex has no hook surface in use here (`~/.codex/hooks.json` is empty), so Codex is covered by its instructions and the usage read; (d) the Slack sending route β€” already gated on 30 Sep, its selftest is re-run here and nothing else; (e) security and privacy work, always; (f) the retired Rafter block in `~/.codex3/AGENTS.md` beyond leaving it below the managed block.
- **Trip-over protocol:** a lane that finds something outside the fence writes one handover line to its named owner (a security- or privacy-shaped thing: one line in `projects/ops/sp-sec/PLAN.md`), then back to building β€” never investigates, never fixes.

## 1a Β· Critical variables β€” the confirmation sheet is GENERATED from this table

| # | The variable, in plain words | Value chosen | Alternatives rejected | Class | HOW WE KNOW | Cost if wrong | CONFIRMED |
|---|---|---|---|---|---|---|---|
| 1 | **SURFACE β€” which screen this lands on, and who opens it** | No screen. The agent's own session (a refusal) and the Hub card for Nick | A Hub screen for DeepAPI spend | V1 | Nick, 30 Sep 2026, "go ahead and build it" on the triad's version, which named no screen | A screen nobody asked for | Nick, 2026-09-30, "go ahead and build it" |
| 2 | Which DeepAPI routes need a stated reason | Web search, page read, deep research, deep scrape, extract, PDF, GitHub, browser | Hard refusal with no override | V1 | RULE 61 (Nick, 2026-09-20) names these as native-first and calls deep research "a decision, not a default" | Agents blocked from a real fallback | Nick, 2026-09-20, RULE 61 "Would the native tool FAIL, or merely be less convenient?" |

**Considered and ruled NOT critical:**
- The override's wording β€” any `NATIVE-FAILED: <reason>` of 15+ characters; the log is what matters.

## 1b Β· Subproject decomposition β€” could a piece of this ship on its own?

- **SINGLE SUBPROJECT:** every piece serves one rule and ships through the same sync job; each step below goes live on its own as it closes.

## 2 Β· The complete UX map (this becomes the test manifest verbatim)

| Id | Screen / entry point | State (defaultΒ·emptyΒ·errorΒ·loading) | Element / interaction | Expected behavior | Navigation from β†’ to |
|---|---|---|---|---|---|
| U1 | Claude Bash, any folder | default | command calling DeepAPI web search | refused, names WebSearch and the override | agent β†’ WebSearch |
| U2 | Claude Bash, any folder | override | same command with `NATIVE-FAILED: <reason>` | allowed, logged | agent β†’ DeepAPI |
| U3 | Claude Bash, any folder | default | command calling DeepAPI LinkedIn/YouTube/Reddit/SEO/image | allowed | agent β†’ DeepAPI |
| U4 | Codex, any folder | default | session start | AGENTS.md carries the native-first block | β€” |
| U5 | Any agent reading the DeepAPI skill | default | skill description and endpoint table | states RULE 61 first; no paid-first or 5+ search order | β€” |
| U6 | Vendor updater | error | SKILL.md deleted then updater runs | vendor copy returns; next sync re-applies the house copy | β€” |
| U7 | HEARTBEAT | error | unexplained paid web search in a day | deepapi-watch row turns red with the count | watchers β†’ agent |

## 2d Β· DESIGN FIDELITY GATE: N/A β€” nothing rendered

## 3 Β· Lanes and frozen contracts

| Lane | Scope (in / out) | Owner | Definition of done | Builder (cheap, named) | Backup builder | Checker (different model) | Backup checker |
|---|---|---|---|---|---|---|---|
| Guard | gate, sync, rule text, watch / not Muse, not Codex hooks | Nick | FINISH LINE 1–6 green | Opus (safety wall, CORE Β§3) | Sonnet | Sonnet verifier | Astra |

**Contracts (FROZEN):** the override token is `NATIVE-FAILED:`; the managed block markers are `<!-- native-first:start -->` / `<!-- native-first:end -->`; the patched skill carries the marker line `house-rule: native-first (RULE 61)`; the Muse call log is `content-discovery-deepapi-calls.jsonl` in the skippy-jobs state folder, one JSON line per paid call `{at, capability, requestId}`.

## 3b Β· Execution map β€” the Step map, then one STEP block per row

A task is DONE only when its review-ledger row is CLOSED by a reviewer that is not the builder.

**Step map (read this first):**

| Stage | # | Task (step name) | Needs (named artefact, or `none β€” start now`) | EXECUTOR (cheap model) | EXECUTOR BACKUP | CHECKER (different model) | CHECKER BACKUP | DONE-PROOF (runnable command) |
|---|---|---|---|---|---|---|---|---|
| Framing | 1 | The gate | none β€” start now | Opus (safety wall) | Sonnet | Sonnet verifier | Astra | `node ZION/lib/_test-check-deepapi-native-first.mjs` |
| Framing | 2 | Rules and wiring on every Mac | none β€” start now | Opus (safety wall) | Sonnet | Sonnet verifier | Astra | `node ZION/lib/native-first-sync.mjs --check` |
| Tests | 3 | Vendor updater cannot undo it | the sync script from STEP 2 | Opus | Sonnet | Sonnet verifier | Astra | `node ZION/lib/_test-native-first-updater.mjs` |
| Elements | 4 | Daily usage read | none β€” start now | Sonnet | Qwen | Opus | Astra | `node projects/ops/skippy-jobs/jobs/deepapi-watch.mjs --selftest` |
| Details | 5 | The rule files tell the truth | the sync script from STEP 2 | Opus | Sonnet | Sonnet verifier | Astra | `command grep -c "does not hold" projects/ops/blocks/BUILD.md` |
| Proof | 6 | Fresh sessions pick the free tool | STEP 1 and STEP 2 closed | Opus | Sonnet | Astra | Fable | `node ZION/lib/native-first/fresh-session-test.mjs` |
| Proof | 7 | Every Mac read back | STEP 2 closed | Opus | Sonnet | Astra | Fable | `node ZION/lib/native-first-sync.mjs --readback` |
| Output | 8 | Sign-off and postmortem | STEPS 1–7 closed | Opus | Fable | Astra | Fable | `python3 projects/ops/agents/check_plan.py <this plan>` |

### STEP 1 β€” The gate
**FOR NICK:** agents stop spending on DeepAPI searches and page reads out of habit; the platforms only DeepAPI can reach still work. Β· **Tier:** FRONT
**Start when:** none β€” start now.
**Builder:** Opus (safety wall, CORE Β§3) Β· **Builder backup:** Sonnet Β· **Checker:** Sonnet verifier Β· **Checker backup:** Astra
**Files you may touch:** `ZION/lib/check-deepapi-native-first.mjs`, `ZION/lib/_test-check-deepapi-native-first.mjs`, `.claude/settings.json` (one Bash hook entry). **Never** the Muse job's content-discovery folder (Muse lane).

**Do exactly this:**
1. Write the gate: read the hook JSON on stdin, take `tool_input.command`, refuse (exit 2, message on stderr) when it names a DeepAPI host or `DEEPAPI_` variable together with a native-first route and carries no `NATIVE-FAILED:` reason of 15+ characters; append every allowed override to `~/.deepapi/native-failed.log`.
2. Write the selftest: refused, allowed, override, unrelated-command and evasion cases (quoted path in a heredoc, `$BASE/v1/search/web`, mixed case), red first against a stub that allows everything.
3. Add the hook to `.claude/settings.json` under the Bash matcher through `projects/ops/hooks/run-node-hook.sh`.

**DEFINITION OF DONE:** the selftest passes every case and fails against the allow-everything stub.
**PROOF:** `node ZION/lib/_test-check-deepapi-native-first.mjs` β†’ `ALL PASS` Β· **FAILS IF:** any `FAIL` line, or the stub run passes.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once, and one live refusal in a real session. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 2 β€” Rules and wiring on every Mac
**FOR NICK:** Codex and every installed copy of the DeepAPI skill now say "free tools first", and every Claude session on the Mac has the gate, without anyone remembering to install it. Β· **Tier:** FRONT
**Start when:** none β€” start now.
**Builder:** Opus (safety wall, CORE Β§3) Β· **Builder backup:** Sonnet Β· **Checker:** Sonnet verifier Β· **Checker backup:** Astra
**Files you may touch:** `ZION/lib/native-first-sync.mjs`, `ZION/lib/native-first/RULE-BLOCK.md`, `ZION/lib/native-first/SKILL-HOUSE-BLOCK.md`, `ZION/lib/install-skills.sh` (one line in `--cloud`); on each Mac: `~/.codex*/AGENTS.md` (not `~/.codex2`), installed `deepapi/SKILL.md` copies, `~/.claude/settings.json` (one hook entry). **Never** `~/.codex2/*` (Chantelle's account).

**Do exactly this:**
1. Write the rule text once in `ZION/lib/native-first/`.
2. Write the sync: idempotent managed block in each Codex AGENTS.md; patched skill from the vendor's current copy (kept fresh daily by running the vendor updater against `~/.deepapi/pristine-home`); the gate hook in user settings pointing at the cloud copy; `--check` exits 1 naming each item not in place.
3. Call it from `install-skills.sh --cloud`.

**DEFINITION OF DONE:** on the Studio, `--check` prints every item green after one sync run, and a second run changes nothing.
**PROOF:** `node ZION/lib/native-first-sync.mjs --check` β†’ `native-first: all in place` Β· **FAILS IF:** any `MISSING` or `STALE` line, or the second run reports a write.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 3 β€” Vendor updater cannot undo it
**FOR NICK:** the vendor's daily self-update can no longer put "use DeepAPI for everything" back. Β· **Tier:** POLISH
**Start when:** the sync script from STEP 2 exists.
**Builder:** Opus Β· **Builder backup:** Sonnet Β· **Checker:** Sonnet verifier Β· **Checker backup:** Astra
**Files you may touch:** `ZION/lib/_test-native-first-updater.mjs`. **Never** the live `~/.agents`, `~/.claude`, `~/.codex` skill copies (the test runs in a throwaway home).

**Do exactly this:**
1. In a temporary home: install the vendor copy with the real updater; run the sync; run the updater with `--force`; assert the house copy survived. Delete SKILL.md; run the updater; assert the vendor copy returned; run the sync; assert the house copy is back.

**DEFINITION OF DONE:** all four assertions pass with the real vendor updater.
**PROOF:** `node ZION/lib/_test-native-first-updater.mjs` β†’ `ALL PASS (4/4)` Β· **FAILS IF:** any assertion fails.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 4 β€” Daily usage read
**FOR NICK:** if any agent or job starts paying for searches the free tools do, it shows up within a day instead of on the bill. Β· **Tier:** FRONT
**Start when:** none β€” start now.
**Builder:** Sonnet Β· **Builder backup:** Qwen Β· **Checker:** Opus Β· **Checker backup:** Astra
**Files you may touch:** `projects/ops/skippy-jobs/jobs/deepapi-watch.mjs`, `projects/ops/skippy-jobs/lib/content-discovery/providers.mjs` (one append of the call log after a reply; handover line to the Muse plan). **Never** the Muse job's spend rules.

**Do exactly this:**
1. Muse: append `{at, capability, requestId}` to the frozen call log after each DeepAPI reply.
2. Watch: once a day, read `/v1/usage` for today; red when search.web + scrape.website + research.deep + scrape.extract exceeds the Muse log's count for the day; print the excess in the HEARTBEAT line. Add a `--selftest` mode covering red on excess and green on a Muse-only day.

**DEFINITION OF DONE:** the selftest proves red on an excess and green on a Muse-only day, and the live run prints today's numbers.
**PROOF:** `node projects/ops/skippy-jobs/jobs/deepapi-watch.mjs --selftest` β†’ `ALL PASS` Β· **FAILS IF:** any `FAIL`, or the live run cannot read usage.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

**Handoff (if any):** one dated line into the Muse plan: `STEP 4 closed <date> β€” every paid DeepAPI call now also writes one line to the call log.`

### STEP 5 β€” The rule files tell the truth
**FOR NICK:** the house rules stop telling agents the vendor file cannot be fixed. Β· **Tier:** POLISH
**Start when:** the sync script from STEP 2 exists.
**Builder:** Opus Β· **Builder backup:** Sonnet Β· **Checker:** Sonnet verifier Β· **Checker backup:** Astra
**Files you may touch:** `projects/ops/blocks/BUILD.md` Β§4, `projects/ops/MACHINE-RULES.md` RULE 61, `GLOBAL-CLAUDE-RULES.md` (the DeepAPI line). A refused governed write is ticketed and work continues.

**Do exactly this:**
1. Replace "editing it there does not hold" and "cannot be durably edited here" with: the sync keeps a house copy that the vendor updater leaves alone.

**DEFINITION OF DONE:** no rule file still says the vendor file cannot be edited.
**PROOF:** `command grep -c "does not hold" projects/ops/blocks/BUILD.md` β†’ `0` Β· **FAILS IF:** a non-zero count, or the same claim in MACHINE-RULES or GLOBAL-CLAUDE-RULES.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 6 β€” Fresh sessions pick the free tool
**FOR NICK:** proof that a brand-new agent, given an ordinary lookup, uses the free tool without being told. Β· **Tier:** POLISH
**Start when:** STEP 1 and STEP 2 closed (their VERIFIED lines below).
**Builder:** Opus Β· **Builder backup:** Sonnet Β· **Checker:** Astra Β· **Checker backup:** Fable
**Files you may touch:** `ZION/lib/native-first/fresh-session-test.mjs`. **Never** a paid DeepAPI call during the test (the gate is on; the prompt is an open-web lookup).

**Do exactly this:**
1. Start fresh sessions with the same ordinary lookup (Claude in a temp folder, Claude in the workspace, Codex in a temp folder, Codex in the workspace, Claude dispatching a helper); record every tool call; pass when the lookup used the free tool and no DeepAPI search or page-read route appears.

**DEFINITION OF DONE:** every session passes.
**PROOF:** `node ZION/lib/native-first/fresh-session-test.mjs` β†’ `5/5 PASS` Β· **FAILS IF:** any session called a DeepAPI search or page-read route, or never looked anything up.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 7 β€” Every Mac read back
**FOR NICK:** a list of every Mac that is covered, and the ones that are not, by name. Β· **Tier:** FRONT
**Start when:** STEP 2 closed.
**Builder:** Opus Β· **Builder backup:** Sonnet Β· **Checker:** Astra Β· **Checker backup:** Fable
**Files you may touch:** none beyond STEP 2's files. This step reads.

**Do exactly this:**
1. Run `--check` on the Studio and over ssh on the Mac mini after their sync has pulled the push; write each Mac's result here; write every Mac not reachable by ssh as NOT DONE with the reason.

**DEFINITION OF DONE:** every reachable Mac reads `all in place`; every other Mac is named NOT DONE.
**PROOF:** `node ZION/lib/native-first-sync.mjs --readback` β†’ one line per Mac Β· **FAILS IF:** a reachable Mac shows MISSING or STALE.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

### STEP 8 β€” Sign-off and postmortem
**FOR NICK:** one message saying what is covered, what was proven, and what is not. Β· **Tier:** POLISH
**Start when:** STEPS 1–7 closed.
**Builder:** Opus Β· **Builder backup:** Fable Β· **Checker:** Astra Β· **Checker backup:** Fable
**Files you may touch:** this plan and `evidence/reviews/` beside it (the file gate allows one governing .md per project, so the postmortem lives in this plan).

**Do exactly this:**
1. Astra reads the closed steps' proofs and returns SHIP or NOT; write the postmortem into this plan's POSTMORTEM section.

**DEFINITION OF DONE:** Astra returns SHIP.
**PROOF:** `python3 projects/ops/agents/check_plan.py <this plan>` β†’ passes, and Astra's verdict file reads SHIP Β· **FAILS IF:** NOT SHIP.

**If the check fails:** the builder fixes and re-checks the named failure until it passes. If this step cannot close from this machine: one line to the overseer naming the ONE missing thing, then the next step whose inputs exist.

**Checker's job:** re-run the PROOF yourself, once. PASS closes the step. Do not accept the builder's pasted output; do not summon anyone else.

## 4 Β· Regret Check (the registry failures this build is actually exposed to)

| Failure mode (registry entry) | The measure in THIS plan that prevents it | Where it lives (section / artifact / gate) |
|---|---|---|
| A guard never seen to fail | selftest runs red against an allow-everything stub first | STEP 1 |
| A text-matching guard missing wrapped or alternative forms | evasion cases in the selftest (heredoc, variable base, case) | STEP 1 |
| A fix that lives only on one Mac | everything runs from the cloud copy via the 30-minute sync | STEP 2, STEP 7 |
| Files on disk taken as proof the rule loaded | fresh sessions judged by the tool actually used | STEP 6 |
| A detector that alarms forever on legitimate traffic | Muse's own calls subtracted before red | STEP 4 |
| A vendor update silently undoing the fix | real-updater test in a throwaway home | STEP 3 |
| An unreachable store read as empty | unreachable Macs written NOT DONE, never green | STEP 7 |

## 5 Β· Topology and roles
- **OVERSEER-AUTHORITY:** none named. **The four approval classes (money leaving Β· credential rotation Β· irreversible destruction Β· a message sent as Nick) and the floor (logins Β· credentials, tokens and keys Β· government IDs Β· card, bank and routing numbers) never move on the overseer's word.**
- Thread layout: one overseer thread (this session); checkers as separate dispatches.
- Overseer: Opus Β· Workers: Opus/Sonnet builders, Sonnet/Astra checkers Β· Cap: 8 per session
- State files location: this plan (no state file).
- **Board card id:** `ac-ai-builds-ops-native-first-routing-free-search-first-paid-`
- **Artefact consumers:** the gate β†’ every Claude session; the sync β†’ each Mac's 30-minute job; the usage read β†’ HEARTBEAT and its watchers.
- **Write-contention:** only this lane writes `ZION/lib/*native-first*`; the one line in the Muse providers file is announced in the Muse plan.

| Stage | Overseer | Sub-overseers | Workers |
|---|---|---|---|
| 1 | 1 | 0 | 3 |

- **STATE FILE:** this PLAN.md
- **HEARTBEAT ROW:** `deepapi-watch`
- **MORNING-REPORT LINE:** none β€” the card carries the status

## 6 Β· Evals β€” what "working" means, decided now

| Capability | Check (exact command or procedure) | Pass looks like |
|---|---|---|
| 1 gate | `node ZION/lib/_test-check-deepapi-native-first.mjs` | ALL PASS, stub red |
| 2 Codex rule | `node ZION/lib/native-first-sync.mjs --check` | all in place |
| 3 skill copy | `node ZION/lib/_test-native-first-updater.mjs` | 4/4 |
| 4 user-level wiring | `node ZION/lib/native-first-sync.mjs --check` | hook line present |
| 5 usage read | `node projects/ops/skippy-jobs/jobs/deepapi-watch.mjs --selftest` | ALL PASS |
| 6 fresh sessions | `node ZION/lib/native-first/fresh-session-test.mjs` | every session PASS |
| 7 readback | `node ZION/lib/native-first-sync.mjs --readback` | one line per Mac |

## If you get stuck (all steps)

Before writing "blocked": (1) re-read the step's START WHEN line β€” most "stuck" is a misread gate, (2) try a concrete workaround, (3) write one line to the overseer naming the ONE missing artefact. Then keep working every other step whose inputs exist. Never idle on a blocker; never end a turn waiting on a background result.

## Your loop

Every pass: every step whose START WHEN inputs exist and which is not yet CLOSED is running, up to the cap β†’ each builder runs its own PROOF, hands to its checker β†’ PASS closes it, FAIL loops it β†’ repeat until the FINISH LINE is proven.

## LANDED FOR MACHINE RESTART β€” Thu 1 Oct 2026, 7:15 am

**1 Β· Pick-up prompt:** `Read projects/ops/native-first/PLAN.md, block "LANDED FOR MACHINE RESTART β€” Thu 1 Oct 2026, 7:15 am"; first check whether Nick approved ticket request a074aeb7 (projects/ops/skippy-jobs/state/ticket-requests.jsonl) and, if so, make the one-sentence RULE 61 edit in projects/ops/MACHINE-RULES.md.`

**2 Β· State, measured at landing (7:12 am):**
- Live: the gate at commit `6becbe4de1` (last change), run by every Claude config folder on the Studio (`~/.claude`, `~/.claude-eight`, `~/.claude-jobs`) and the Mac mini (`~/.claude`); `--readback`: Studio all in place (11 items), mini all in place (4 items, cloud copy `24759d213e`); Chantelle's Mac and teammates' Macs NOT DONE (no route).
- Running: nothing of this session's (no loop, no background job, no worktree). The skills sync (every Mac, every 30 minutes) and `deepapi-watch` (Studio, hourly; last OK 7:04 am) run on their own schedules.
- Switched on: user-level Bash hook for the gate in the three Studio config folders and the mini's; the native-first block in `~/.codex`, `~/.codex3`, `~/.codex4`, `~/.codex5` (Studio) and `~/.codex` (mini); house copy of the vendor DeepAPI skill in `~/.agents`, `~/.claude`, `~/.codex` skill folders (Studio); the Muse call log (36 lines at landing).
- Tests at landing: gate 80 cases + 5 end-to-end ALL PASS; watch selftest 25/25; sync selftest 8/8.
- Held: STEP 5's last sentence (MACHINE-RULES RULE 61) β€” ticket request `a074aeb7`, filed 7:14 am, waits on Nick's tap (requests expire after an hour; re-file when it expires).

**3 Β· Done this run:** the whole plan, steps 1–4 and 6–8 at 100% (Astra SHIP on round 13, 10:21 pm); gate 23 β†’ 80 test cases; review rounds 0 β†’ 13 with every finding a test case; Muse handoff line merged in the Hub repo (PR #3610).

**4 Β· Postmortem (landing):**
- Went well: two cold reviewers who never saw each other, a tie-breaker who checked the disputed fact first, and a reviewer told to break the gate rather than re-run its tests β€” that is what turned a gate that blocked ordinary work into one that does not.
- Went wrong: the approval queue is a tracked file in a checkout the Studio's sync reverts. Request `d683813c` was erased at 9:22 pm before Nick saw it; `5099c7f5` reached Slack but expired untapped at 11:42 pm and the queue was reverted again at 1:48 am. Rule: after filing a ticket request, read the queue back for its id before telling anyone it is waiting, and re-read it at landing.
- Went wrong: twelve review rounds, each finding one narrower case. Rule: ask the reviewer to rate BLOCKER/MINOR and to judge convergence from round 1, not round 7.

**5 Β· Ideas for next steps (ranked):**
1. Fix the Studio sync that reverts tracked files and drops approval rows (task chip "Fix the Studio sync that erases approvals and edits" in Nick's sidebar; evidence: `git log -S5099c7f5` finds the row only on branch `mac/nicks-mac-studio-presync-20261001-night`).
2. Make the approval queue untracked or append-only on every sync path, so a revert can never drop a pending request.
3. Read back Chantelle's Mac: ask her session to run `node ZION/lib/native-first-sync.mjs --check` from her Mac's cloud copy of the skills and paste the summary line into STEP 7.
4. Publish this project's status page once the Studio checkout is level with the cloud (status-regen refuses to deploy from a behind checkout, and a fresh worktree would deploy one page over the whole site).

**6 Β· Held for a person:** none. Nick approved `a074aeb7` at 7:14 am on 1 Oct; the RULE 61 edit landed as `af946d3310` and was independently checked at 7:33 am (STEP 5 closed).

## SUMMARY β€” a few plain-English lines, read by the status generator

Finished and signed off on 30 September 2026 at 10:21 pm, live on Nick's Mac Studio and Mac mini. Every Claude session on both Macs has a gate that refuses a paid DeepAPI web search or page read unless the agent says what the free tool failed to do, and lets ordinary work (searching code, reading free docs, committing) through; Codex on both Macs and every copy of the DeepAPI skill carry the free-tools-first rule, and the vendor's daily update cannot undo it. An hourly check compares DeepAPI's own count of paid searches with the ones the approved Muse research job made: an unexplained one fails, one with a stated reason is shown as a warning with that reason. Five brand-new agent sessions, Claude and Codex, inside and outside the workspace, all used free search for an ordinary lookup. Astra signed it off on the thirteenth round. Still open: Nick's one-tap approval to correct one sentence in the rulings file, and Chantelle's and the teammates' Macs, which pick the change up on their own but which nothing here can read back.

## SUMMARY

**2026-10-01** β€” Finished on 1 October 2026 at 7:33 am, live on Nick's Mac Studio and Mac mini. Every Claude session on both Macs refuses a paid web search or page read through DeepAPI (the research service that bills per call) unless the agent says what the free search tool failed to do, and lets ordinary work through. OpenAI's Codex agent and every copy of the DeepAPI instructions carry the same free-tools-first rule, and the automatic update DeepAPI runs once a day cannot undo it. An hourly check compares DeepAPI's count of paid searches with the ones made by the content-ideas research job Nick approved on 30 September: an unexplained search fails the check, one with a stated reason shows as a warning. Nick approved the last correction to the written rule at 7:14 am and it is in place. Nothing is open; Chantelle's and the teammates' Macs apply the change on their own but cannot be checked from here.

**2026-10-01** β€” Finished and signed off on 30 September 2026 at 10:21 pm, live on Nick's Mac Studio and Mac mini. Every Claude session on both Macs now refuses a paid web search or page read through DeepAPI (the research service that bills per call) unless the agent says what the free search tool failed to do, and lets ordinary work through. OpenAI's Codex agent and every copy of the DeepAPI instructions carry the same free-tools-first rule, and the automatic update DeepAPI runs once a day cannot undo it. An hourly check compares DeepAPI's count of paid searches with the ones made by the content-ideas research job Nick approved on 30 September: an unexplained search fails the check, one with a stated reason shows as a warning. Five brand-new agent sessions all used free search for an ordinary lookup. Still open: Nick's one-tap approval, already on his phone, to correct one out-of-date sentence in the rule about DeepAPI; and Chantelle's and the teammates' Macs, which apply the change on their own but cannot be checked from here.

## STEPS

```
1. [Framing] The gate β€” 100%
   DEFINITION OF DONE: selftest passes every case and fails against the allow-everything stub
   PROOF: `node ZION/lib/_test-check-deepapi-native-first.mjs`
   VERIFIED: 2026-09-30 (100%, checked by Astra round 13 β€” five routine commands allowed, three plain paid calls refused, no finding; 80 cases + 5 end-to-end pass, an allow-everything stub fails 51; every evasion and false refusal found by the Sonnet verifier and Astra rounds 1–12 is a case; live refusal seen in a real session at 10:18 pm)
2. [Framing] Rules and wiring on every Mac β€” 100%
   DEFINITION OF DONE: --check all in place on the Studio; a second run writes nothing
   PROOF: `node ZION/lib/native-first-sync.mjs --check`
   VERIFIED: 2026-09-30 (100%, checked by Sonnet verifier β€” "native-first: all in place (11 items)", ~/.codex starts with the block, ~/.codex2 untouched, hook count 1; sync selftest 8/8 incl. Codex2 by link)
3. [Tests] Vendor updater cannot undo it β€” 100%
   DEFINITION OF DONE: four assertions pass with the real vendor updater in a throwaway home
   PROOF: `node ZION/lib/_test-native-first-updater.mjs`
   VERIFIED: 2026-09-30 (100%, checked by Sonnet verifier β€” ALL PASS (4/4, plus setup))
4. [Elements] Daily usage read β€” 100%
   DEFINITION OF DONE: red on excess, green on a Muse-only day, live run prints today's numbers
   PROOF: `node projects/ops/skippy-jobs/jobs/deepapi-watch.mjs --selftest`
   VERIFIED: 2026-09-30 (100%, checked by Astra β€” selftest 25/25; the Muse race PASS (round 2), the in-flight wait PASS (round 4), an unused stated fallback now surfaces as WARN with its reason and an unexplained call as FAIL (round 5); live: green, every paid search/page call today the Muse job's)
5. [Details] The rule files tell the truth β€” 100%
   DEFINITION OF DONE: no rule file says the vendor file cannot be edited
   PROOF: `command grep -c "does not hold" projects/ops/blocks/BUILD.md`
   VERIFIED: 2026-09-30 (67%, checked by Astra β€” BUILD Β§4 and the global rules corrected; projects/ops/MACHINE-RULES.md line 816 still says "cannot be durably edited here", ticket d683813c waits on Nick's one-tap approval)
   VERIFIED: 2026-10-01 (100%, checked by Sonnet verifier against origin/main af946d3310 β€” "does not hold" in BUILD 0, "cannot be durably edited" in MACHINE-RULES 0, the old vendor line in the global rules 0, the ENFORCED line in RULE 61 present once; Nick approved ticket a074aeb7 at 7:14 am)
6. [Proof] Fresh sessions pick the free tool β€” 100%
   DEFINITION OF DONE: every fresh session used the free tool
   PROOF: `node ZION/lib/native-first/fresh-session-test.mjs`
   VERIFIED: 2026-09-30 (100%, checked by Astra reading the transcripts in evidence/fresh-sessions-2026-09-30 β€” five of five used free web search or fetch, none attempted a paid route; note: the dispatched helper was briefed with the rule by its parent session, which is how every dispatched agent here receives its rules)
7. [Proof] Every Mac read back β€” 100%
   DEFINITION OF DONE: every reachable Mac all in place; every other Mac named NOT DONE
   PROOF: `node ZION/lib/native-first-sync.mjs --readback`
   VERIFIED: 2026-09-30 (100%, checked by Sonnet verifier β€” Studio all in place (11 items); Mac mini all in place (4 items), confirmed first-hand over ssh; Chantelle's Mac and the teammates' Macs NOT DONE, no route from the Studio)
8. [Output] Sign-off and postmortem β€” 100%
   DEFINITION OF DONE: Astra returns SHIP on the closed steps' proofs
   PROOF: `python3 projects/ops/agents/check_plan.py <this plan>`
   VERIFIED: 2026-09-30 (100%, checked by Astra β€” rounds 1–12 NOT SHIP, each finding fixed, tested and landed; round 13 SHIP at 10:21 pm, evidence/reviews/15-astra-signoff-round13-SHIP.txt; postmortem below)
```
   VERIFIED: 2026-09-30 (100%, checked by Astra β€” rounds 1–12 NOT SHIP, each finding fixed, tested and landed; round 13 SHIP at 10:21 pm, evidence/reviews/15-astra-signoff-round13-SHIP.txt; postmortem in the plan)

## POSTMORTEM β€” 30 September 2026

**How the scope was set.** Nick: "dont take it as gospel get fable and astra cold review on the recs and you tie break as the third leg of triad". Both cold reviews said PROCEED WITH CHANGES. Ties broken: "find Slack unaided" cut (not measurable; Slack sending was already gated that morning); convenience-versus-failure kept as fixed gate cases, not a model's judgement; deep research refused only without a stated reason (RULE 61 calls it "a decision, not a default"); fresh sessions judged by the tool actually used, not by reciting the rule; the word "permanent" dropped. One reviewer claim checked before it shaped the plan: the vendor updater does keep an edited skill file (BUILD Β§4 had said the opposite).

**What went wrong or slower than it should have.** (1) A text gate is an arms race in both directions: the Sonnet verifier and Astra's first three rounds found ways to spell a paid address past it, and rounds 3–12 then found ordinary commands it refused (searching code, printing examples, Python and shell scripts, combined commands, pipelines). Thirteen rounds converged on one design: a command is split into its steps and pipeline stages; each is a call only when a request tool or a program's own code makes it, and only its own address is judged; text a shell is handed is a script of its own. Lesson kept: test a guard for false refusals as hard as for misses, and keep DeepAPI's own daily count as the net for what text cannot show. (2) The plan gate refused a landing because a fresh landing worktree reads zero board cards and called that "card does not exist"; fixed in the plan checker (zero cards is NOT MEASURABLE). (3) The Studio's working checkout sits 290 commits behind the cloud and its own sync put five of this lane's files back to the older copy at 9:22 pm; restored from the cloud copy, where each differed only by this lane's commits. That checkout gap belongs to the auto-pull owner (its row reads FAIL, "needs a person to inspect it"). (4) Codex refuses to start outside a git repository, which made the first projectless Codex run unmeasurable; the test now uses an empty repository. (5) The cheap lane refuses the Muse job file because it reads a key, so that edit was made here.

**What to keep.** Two cold reviewers who never see each other, then a tie-breaker who checks the disputed fact first; a checker who tries to break the gate rather than re-run its tests; evidence saved beside the plan.