next-expo-supabase-agent-harness
Health Warn
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 8 GitHub stars
Code Fail
- exec() — Shell command execution in .claude/hooks/posttool-factory-check.mjs
- spawnSync — Synchronous process spawning in .claude/hooks/posttool-factory-check.mjs
- process.env — Environment variable access in .claude/hooks/posttool-factory-check.mjs
- rm -rf — Recursive force deletion command in .claude/hooks/pretool-bash-guard.mjs
- process.env — Environment variable access in .claude/hooks/pretool-write-guard.mjs
- spawnSync — Synchronous process spawning in .claude/hooks/stop-factory-gate.mjs
- process.env — Environment variable access in .claude/hooks/stop-factory-gate.mjs
- rm -rf — Recursive force deletion command in .claude/settings.json
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
A CLI that scaffolds a Next.js and Expo (React Native) monorepo on Supabase, with Claude Code hooks and CI gates that block an agent turn or a merge until validation passes.
next-expo-supabase-agent-harness
A CLI that scaffolds a pnpm monorepo with a Next.js 16 web app and an Expo 57
(React Native) mobile app on one Supabase backend, plus Claude Code hooks and CI
gates that block an agent turn or a merge until validation passes.

No model runs in the recording. The hooks are programs that read the JSON payload Claude
Code hands them, and the gates are programs that exit 1, so what they print is what the
agent is shown. It is generated from
docs/media/harness-demo.tape, and a test runs that script's
commands against each change, so a message that changes reds until the recording is
regenerated.
The npm package is this CLI. npx downloads it and runs it in one step, from an empty
folder for the new project:
npx --yes next-expo-supabase-agent-harness@latest init
Or install it globally once:
npm i -g next-expo-supabase-agent-harness
and then, from an empty folder for the new project, run:
next-expo-supabase-agent-harness init
Either way, init asks for the project's details before it writes anything: its name, its
package name, the app identifier, the Supabase project ref, the GitHub owner and a few more.
Each question shows a default in brackets that Enter accepts, and init --yes accepts them
all without asking. The scaffold is written into the current folder.
Install with -g: a local npm i writes a package-lock.json into the folder, and init
stops when it finds one. A global install stays at the version you installed, so runnpm i -g next-expo-supabase-agent-harness@latest before update to move it to the newest
release; update refuses to run from a CLI older than the project.
To pin a release, take a version number from the
Releases
page (the tag without its v) and use it in place of latest, or installnext-expo-supabase-agent-harness@<version>. Once init has finished, in the same folder:
git init # first: the prepare script (lefthook install) needs a repository
pnpm install
git add -A && git commit -m "chore: scaffold" # the first commit must include pnpm-lock.yaml
pnpm validate
Status: stable (2.0.x). CI proves the scaffold on Linux, and on macOS without
the database gates. The installer's unit tests run on Linux, Windows and macOS.pnpm validate has never run in CI on Windows. See Limitations.
Who this is for
The harness assumes one shape: a pnpm monorepo with a Next.js web app and an Expo mobile
app on one Supabase backend, Node 22 or newer, Docker for the local database the database
gates run against, and Claude Code as the agent, because Claude Code is what runs the
hooks that block a turn. Enforcement comes in layers: the Claude Code hooks, the lefthook
commit hooks, pnpm validate, and CI. Outside that shape, some layers still apply:
- A web-only app. Not a fit today.
initwrites both apps, and the mobile gates
judgeapps/mobile. Without it,expo-policyandnative-depsskip on a laptop but
fail closed in CI, andparitygoes red on the mobile paths its register names. CI
runs the frozen step list, so a project cannot drop those gates. - An existing monorepo with its own CI.
initretrofits a pnpm workspace that hasapps/weborapps/mobile. It keeps your configs and parks the harness's beside them
as<name>.harness.<ext>files, andgate-integritystays red until each one is merged
or accepted after review. It keeps a workflow file you already have, so your ownci.ymlruns no harness gate until you add the chain to it, and an existinglefthook.ymlis one of the parked configs. The Claude Code hooks are merged into your.claude/settings.json. A repository on npm, yarn or bun, or withoutpnpm-workspace.yaml, is refused. - An agent that is not Claude Code. The commit hooks,
pnpm validateand CI apply as
they do for a person. The.claude/hooks never run, so nothing denies a command before
it runs or keeps a turn from ending on a red tree: a violation is caught at the commit
or at the pull request instead.
Requirements
- Node 22 or newer
- pnpm 11 (
corepack enablepicks up the pinned version) - Docker, for the local Supabase stack that the database gates run against
- Optional: the
gitleaksbinary. The pre-commit secrets scan prints a skip
notice without it.
What you get
apps/web Next.js 16 App Router. Serves the tRPC API for both clients.
apps/mobile Expo 57, expo-router, React Native 0.86.
packages/api framework-neutral tRPC v11 router
packages/contracts zod DTOs shared by both apps
packages/platform/* env, errors, events, observability, ratelimit, supabase
packages/verticals/* your features (empty until you add one, or init --with-demo)
packages/design-tokens, design-system, design-system-native
supabase/ SQL-first schema, migrations, RLS policies, pgTAP tests, one Edge Function
tools/, .claude/, .github/ the gates, hooks and workflows described below
A default init writes no example feature. init --with-demo adds one worked
feature end to end on both apps (the @app/notes vertical, its screens, routes
and migrations, and its rows in the registers), and eject takes it back out;
see docs/cli.md.
Postgres row-level security keyed on auth.uid() is the one authorization
boundary for both apps. Versions are pinned in a single pnpm catalog
(pnpm-workspace.yaml): Next 16.4, Expo 57, React 19.2, TypeScript 6, Biome 2.6,
supabase-js 2, tRPC 11, zod 4.
How it works
- PreToolUse guards. Hooks check every shell command, file write and MCP
call against a data table of 151 guard-rule ids before the agent's tool runs.
Nine hooks are wired: seven guards, a launcher that fails closed if a hook
cannot load, and a session-start brief. - Stop hook. The agent cannot end a turn until
pnpm validate, the RLS
isolation tests against a real Postgres, both unit suites with coverage,
per-file diff coverage, duplication, i18n, test quality, the mobile perf
closure and the reviewer verdicts all pass. pnpm validate. One chain of 37 gates, ordered cheap to expensive, driven
bytools/harness.config.mjs. Each gate is documented with a proof that it
can fail in the gates catalog.- CI. The same chain runs against a frozen copy of the step list
(tools/validate.floor.json), so a project can add gates but cannot quietly
remove one. Gates that need a database or a toolchain skip loudly on a
laptop and fail closed in CI. - Supply chain. Every workflow the harness ships pins its actions by commit
SHA, and zizmor audits them. OSV-Scanner checks the lockfile for known
vulnerabilities, gitleaks scans for secrets, and the Renovate config lets a
new npm release age (minimumReleaseAge) before proposing it. Theci-provenancemodule adds an SBOM and build provenance attestations. - Commit hooks. lefthook runs Biome and gitleaks before a commit and
commitlint on the message.
The design is described in the
harness doctrine, which ships into every
scaffold. Its
hook map
lists each hook, the event it runs on and what it enforces.
Compared with other starters
Other projects also put a Next.js app and an Expo app in one repository:
- create-t3-turbo is a Turborepo
starter with an Expo app, Next.js and TanStack Start web apps (you pick one),
tRPC, Better Auth, and Drizzle preconfigured for a Supabase Postgres
database. You start from a copy of it, made with GitHub's "Use this template"
button or withnpx create-turbo@latest -e https://github.com/t3-oss/create-t3-turbo. - Solito is a library that unifies
navigation between React Native and Next.js.npx create-solito-app@latest
writes one of its example monorepos; in the default one, both apps render the
same screens from a shared package.
In this harness:
- Authorization is Postgres row-level security keyed on
auth.uid(). Both apps
meet the same policies, and pgTAP and supabase-js suites test them against a
real database. - Claude Code hooks and CI gates block an agent turn or a merge until
validation passes. updateapplies a later harness release to a project that already exists.- The two apps share the API, the contracts and the design tokens, not their
screens.
Commands
| Command | What it does |
|---|---|
init |
Scaffold into --dir (default .). --tier core|standard|strict, --modules a,b, --set VAR=value, --dry-run. |
update |
Apply a newer harness version to an existing install. --rollback restores the tree recorded before the last update. |
doctor |
Report whether an install is healthy. |
enable <module> / disable <module> |
Add or remove an opt-in module. |
graduate |
Advance the install's base version once ramped checks are clean. |
apply-proposal [<id>] |
Apply, as a human in a terminal, a register edit an agent staged in harness-proposals/: it shows the reason and the diff and writes the file once you type its path. No id lists them. --dry-run. |
Full flag and placeholder reference: docs/cli.md, or --help.
Tiers choose which opt-in modules are installed. core installs none.standard (the default) installs ci-provenance, ci-mobile-release andci-web-deploy. strict installs all twelve: those three plus device-e2e,eas-update, store-metadata, gate-a11y-deep, crash-reporting,push-notifications, eval-live, observability and e2ee. The Vercel deploy
workflow, EAS Build/Submit and release-please come from modules, not the base.
Claude Code plugin
The agents, slash commands and skills also come as a Claude Code plugin, for a session
outside a harness-installed project. Install it from this repository's marketplace:
claude plugin marketplace add cogvera-labs/next-expo-supabase-agent-harness
claude plugin install next-expo-supabase-agent-harness@next-expo-supabase-agent-harness
or, inside a session on Claude Code 2.1.275 or later:
/plugin install next-expo-supabase-agent-harness --marketplace cogvera-labs/next-expo-supabase-agent-harness
The plugin carries no hooks, gates or permissions; those come with init. Inside a
harness-installed project you do not need it, and its reviewers' verdicts do not count
toward the reviewer ledger. See plugin/README.md.
Limitations
- The database gates are proven on Linux only. Every CI lane with a
Supabase stack runs onubuntu-latest. Themacos-scaffoldlane runsinitandpnpm validateon a Mac without Docker, the way a laptop runs
them, and fails if any gate skips excepttypes-drift, which needs the
database. No lane runs a scaffold on Windows. - Rate limiting covers the application layer only. It binds the tRPC router
and Next.js Server Actions. It does not bound direct PostgREST calls made
with a user's JWT, or sign-in and sign-up, which go to Supabase Auth. If the
rate-limit backend is unreachable, it degrades to an in-process limiter, and
it fails open if that also fails. - The
e2eemodule ships building blocks, not an encrypted app. No shipped
feature is encrypted; the worked exampleinit --with-demoadds stores
plaintext. The module's own README lists what it does not solve. - Device tests are not per-PR. The Android emulator and Maestro lane runs on
a schedule and on manual dispatch. - The guards are tamper-evident, not tamper-proof. See the scope notes in
SECURITY.md.
The longer list is kept per release under "What stays open" in the
CHANGELOG.
Measured cost
Recorded by CI on a GitHub-hosted Linux x64 runner on 2026-10-02 and committed
in scripts/chain-budget.json. They are that runner's numbers, not a promise
about your machine.
| Run | Wall time |
|---|---|
pnpm validate, warm |
warm ≈ 27 s (26881 ms) |
pnpm validate, cold |
cold ≈ 145 s (145363 ms) |
| Stop hook, full turn end | 54.8 s (54815 ms) |
Compliance mappings
The scaffold ships two registers that map published requirements to the gate,
hook or test that addresses each one, including the requirements it does not
meet. These are mappings. They are not certifications, and the project claims
no conformance level. The gates print the current standing as:
149 ML3 requirements: 8 effective, 13 alternate-control, 11 not-implemented, 61 not-applicable, 56 organisation-boundary; 8 shared clauses
392 mapped requirements: 11 covered, 149 partial, 105 not-covered, 127 not-applicable — ASVS 5.0.0 (345), MASVS 2.1 (24), CRA Annex I (23)
The first line counts the requirements of ASD's Essential Eight
(register). The second
counts the requirements of three further standards
(crosswalk).
Documentation
- Documentation site: the
doctrine, the gates catalog, the runbooks and the module guides, searchable, built from
the same files every scaffold receives - CLI reference: every command, flag and placeholder
- Harness doctrine and
gates catalog, which ship into
every scaffold - Architecture and
security assurance case - Governance, roadmap and changelog
Contributing and feedback
- Bugs and gate proposals: open an issue
- Questions: Discussions
- Pull requests: read CONTRIBUTING.md first. It lists every check CI blocks on.
- Vulnerabilities: report privately, as described in SECURITY.md
- Code of Conduct
To fork the harness itself into a sibling for a different stack, start from a
clone with a fresh history, as docs/forking.md describes.
This repository is descended from
expo-postgres-agent-harness
and
tauri-postgres-agent-harness.
License
Apache-2.0 for the repository. Everything under template/** is
"Apache-2.0 OR 0BSD": recipients choose either, so scaffolded code carries no
attribution requirement.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found