# MOB-29579 — Adopt the mobile Claude Code template (js-ts)

**Jira:** MOB-29579 · **Author:** Özgür Vatansever · **Created:** 2026-09-24 · **Status:** in-progress

## Goal

Bring the repo onto the mobile Claude Code template so every SDK repo shares one rule set, one guard hook and one review contract, while the rules this repo already owns (`CODING.md`, `.claude/rules/unit-tests.md`, orbit docs) stay the source of truth where they overlap. The guard is kept identical to webview-sdk-js's (same lineage), so a fix in one guard is a fix in both.

## Requirements & acceptance criteria

1. `CLAUDE.md` carries the six mandatory sections (Architecture · Commands · Conventions · Testing · Gotchas & Do NOT · Workflow) and stays under the line ceiling.
2. `.claude/rules/` holds the template `core-*` rules without contradicting the repo's own; the language overlay is folded into `CODING.md` (style) and `unit-tests.md` (tests), each the only source for its area.
3. `.claude/hooks/guard.sh` blocks every block case and allows every allow case in `devops/guard_rules_test.sh`; the table runs in CI (`.github/workflows/guard-hook-test.yml`) on any change to the hook or its rule table.
4. `.claude/settings.json` only uses permission forms Claude Code consults (`Edit(...)`, never `Write(...)`); `rm` matches mobile-ios: one worktree path allowed, blanket worktree deletes, multi-target and `..` removals left to the guard.
5. Hooks never report a false reason: no lifetime counters shown as per-session, no path mangled by a rename or a space.
6. Template agents, commands and skills exist and point at repo files that exist.

## Approach

1. Copy the template in and reconcile it with the repo's sources of truth — mirrors mobile-ios `c6da39b5`.
2. Harden the guard with a table test that feeds the real hook, then close every gap a review measured — mirrors webview-sdk-js `23f893f`, `1e0923a`.
3. Port the 23 Sep round from webview-sdk-js (`298fe49`, `d140edc`, `f76e614`, `ec177a7`, `65553c3`, `b3a35cb` — themselves ports of mobileandroid `e17f06e24`, `859d1a199`, `06033befd`), keeping this repo's two fail-closed fixes (root falls back to the cwd; a rule table without a trailing newline keeps its last rule).
4. Align `settings.json` with the policy mobile-ios, mobileandroid and webview-sdk-js share; platform lines stay this repo's own.
5. One source per area, as webview-sdk-js and mobile-ios did: style → `CODING.md`, tests → `unit-tests.md`.

## Files

| Action | Path | Why |
|---|---|---|
| modify | `CLAUDE.md`, `CODING.md` | template structure; single style source |
| add | `.claude/rules/core-*.md` | template rules (`core-testing` folded into `unit-tests.md` and removed) |
| modify | `.claude/rules/unit-tests.md`, `.claude/rules/git-workflow.md` | single test authority; repo git rules |
| add | `.claude/hooks/guard.sh`, `guard-rules.txt`, `format-on-edit.sh`, `session-summary.sh`, `subfolder-claude-md-post-edit.sh` | template hooks |
| modify | `.claude/settings.json` | permissions, hook wiring, `env` |
| add | `devops/guard_rules_test.sh`, `.github/workflows/guard-hook-test.yml` | guard regression coverage |
| add | `.claude/agents/*.md`, `.claude/commands/{pr-body,session-summary}.md`, `.claude/skills/{jira-context,release-prep}` | template agents, commands, skills |
| add | `docs/plans/TEMPLATE.md`, `docs/plans/MOB-29579.md` | plan convention and this plan |
| modify | `.gitignore` | managed block for Claude Code local and generated state |

## Tests

- `bash devops/guard_rules_test.sh` — every block/allow case passes against the real hook (`N passed, 0 failed`).
- `.github/workflows/guard-hook-test.yml` — the same table on a self-hosted runner for PRs touching the guard.
- `npm test` and `bash devops/check_test_groups.sh` — unchanged product tests stay green.

## Out of scope

- Product code under `js/`, `src/`, `types/`, `hooks/`.
- Porting mobileandroid's `guard.sh` itself: it uses a different wrapper architecture and allows an empty payload.

## Risks & rollout

- A guard regex that over-blocks stalls the session — every rule change lands with a table pin; known false blocks (a flag quoted in a commit message, a protected start point in `git branch -f`) are documented in the rule table and the test.
- Removing the blanket `rm -rf *` deny moves ordinary removals to the normal permission flow — the guard still blocks root/home/cwd/parent, `..` traversal, a dangerous second target and blanket worktree deletes.
- Hook and settings edits move from deny to ask, so a session can change its own guard only with a prompt the user answers.

## Changelog

- 2026-09-24 — rebased onto the move from EKB/Atlassian MCP to Zoe (`chore(claude)` commits for MOB-29880): the EKB and Atlassian tool entries in `settings.json` — the `ekb__github` → `ekb__git` fix below included — are replaced by the read-only Zoe tools, Zoe `jira`/`github` calls ask, and `enabledPlugins` is `orbit` + `zoe`. The rest of this port is unchanged.
- 2026-09-24 — ported the 23 Sep sibling round. Guard and table from webview-sdk-js `b3a35cb` (secret rule ignores grep/rg/jq search patterns, payload `cwd`, commit-creating verbs and pushd/popd/GIT_DIR on protected branches, one-worktree `rm`, any-target `rm`, flag-form branch delete/force/move, bundled `-n`/`-f`, `--no-verify` abbreviations and merge/pull/rebase/am, `timeout -s`), keeping this repo's two fail-closed fixes. Settings: dead `Write(...)` rules removed, `rm -rf *` deny and `rm:*` ask removed, worktree allows added, `git stash` ask narrowed to mutating forms, `ekb__github` → `ekb__git`, protected `push -u`/`HEAD:` denies, `env` block, `awk`/`find` allows removed, hook/settings edits ask. Hooks: per-session formatter marker, nested-CLAUDE.md check stops at a checkout root, session summary reads `git status -z`. Style and test overlays folded into `CODING.md` and `unit-tests.md`. Plan file created.
