Skip to content

Commit 8b7f30d

Browse files
Fix agent surface sync boundaries
Signed-off-by: jmclaughlin724 <31931302+jmclaughlin724@users.noreply.github.com>
1 parent a502008 commit 8b7f30d

18 files changed

Lines changed: 795 additions & 210 deletions

File tree

.agents/prompts/supaschema-install.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Use the matching local runner for every command after install:
3838
| Yarn | `yarn exec supaschema <cmd>` |
3939
| Bun | `bunx --no-install supaschema <cmd>` |
4040

41-
Always run the matching explicit setup command from the owning package directory after install. The command is idempotent; it leaves existing config intact and refreshes the managed agent surfaces. `supaschema init` combines the consuming repo's detected package manager, workspace owner, provider markers, schema paths, and migration paths with the packaged supaschema rule, skill, hook, config, and prompt bundle.
41+
Always run the matching explicit setup command from the owning package directory after install. The command is idempotent; it leaves existing config intact, preserves existing hook entries, appends missing supaschema hook entries at the end of the relevant event array, and refreshes the managed agent surfaces. `supaschema init` combines the consuming repo's detected package manager, workspace owner, provider markers, schema paths, and migration paths with the packaged supaschema rule, skill, hook, config, and prompt bundle.
4242

4343
```bash
4444
npm exec -- supaschema init

.agents/skills/supaschema/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ When the bundled PostToolUse hook is wired (`.claude/settings.json` / `.codex/ho
1313

1414
## Installed Setup
1515

16-
The normal consumer setup is package install plus one explicit setup command through the consuming project's package manager. Read `.agents/prompts/supaschema-install.md` before installing, initializing, inspecting, or explaining setup. That prompt owns package-manager detection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. Treat `supaschema.config.json`, installed schema/migration directories, Claude/Codex rule and skill files, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addenda as the package-owned setup surface. Run `supaschema init` through the matching local runner from the schema-owning package directory after install; it is idempotent and uses the package scaffold to refresh managed setup surfaces. The package scaffold installs the full supaschema skill directories directly into `.agents/skills/supaschema` and `.claude/skills/supaschema`; it does not invoke `npx skills`.
16+
The normal consumer setup is package install plus one explicit setup command through the consuming project's package manager. Read `.agents/prompts/supaschema-install.md` before installing, initializing, inspecting, or explaining setup. That prompt owns package-manager detection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. Treat `supaschema.config.json`, installed schema/migration directories, Claude/Codex rule and skill files, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addenda as the package-owned setup surface. Run `supaschema init` through the matching local runner from the schema-owning package directory after install; it is idempotent, preserves existing hook entries, appends missing supaschema hook entries at the end of the relevant event array, and uses the package scaffold to refresh managed setup surfaces. The package scaffold installs the full supaschema skill directories directly into `.agents/skills/supaschema` and `.claude/skills/supaschema`; it does not invoke `npx skills`.
1717

1818
If this skill was installed through `npx skills`, treat it as portable workflow context only. Agent Skills installs `SKILL.md`-based folders into a user-selected skill location; it does not create `supaschema.config.json`, schema/migration directories, passive rule files, hook scripts, or hook registration. To install those project enforcement surfaces, install the npm package with the consuming project's manager from the owning package directory, then run `supaschema init` through the same manager's local runner from that directory. The package scaffold installs the rule and hooks; the `npx skills` lane does not.
1919

.claude/rules/supaschema.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This rule owns how schema migrations are produced and protected in a repo that u
1111
## Rules
1212

1313
- Consumer migration policy must rely on project files, generated hook context, and supaschema command output. Repo-local maintainer tooling such as Code Atlas, cclsp, FastMCP, and context-enforcement hooks is not part of the published consumer install surface.
14-
- Consumer setup is package install plus one explicit setup command with the consuming project's package manager. The agent install protocol lives at `.agents/prompts/supaschema-install.md`; it owns package-manager selection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. The installed config, schema/migration directories, supaschema consumer rule/skill/hook bundle, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addendum are part of the package setup surface. Maintainer-only Claude/Codex optimization and context-enforcement tooling remains repo-local under Rule 13. `supaschema init` performs consumer setup through the shared scaffolder (`bin/scaffold.mjs`) — config, directories, agent bundle, hook wiring, and pending path-confirmation state when needed. Run it through the matching local runner from the schema-owning package directory after install. It is idempotent: existing JSON config files are left untouched unless explicit repair is requested, JavaScript config files are not loaded or converted, and the managed guidance block is upserted in place.
14+
- Consumer setup is package install plus one explicit setup command with the consuming project's package manager. The agent install protocol lives at `.agents/prompts/supaschema-install.md`; it owns package-manager selection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. The installed config, schema/migration directories, supaschema consumer rule/skill/hook bundle, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addendum are part of the package setup surface. Maintainer-only Claude/Codex optimization and context-enforcement tooling remains repo-local under Rule 13. `supaschema init` performs consumer setup through the shared scaffolder (`bin/scaffold.mjs`) — config, directories, agent bundle, hook wiring, and pending path-confirmation state when needed. Run it through the matching local runner from the schema-owning package directory after install. It is idempotent: existing JSON config files are left untouched unless explicit repair is requested, JavaScript config files are not loaded or converted, and the managed guidance block is upserted in place. Hook wiring preserves existing entries and appends missing supaschema hook entries at the end of the relevant event array; it only removes the known broken package-owned Claude script entries that passed `${CLAUDE_PROJECT_DIR}` script paths through `args`.
1515
- Normal resolved installs do not create `.supaschema/`. If `.supaschema/install.json` exists and records `"pathConfirmationNeeded": true`, inspect the detected candidates, ask the user which `schemaPaths`, `sources.to`, and `migrationsDir` to use, and update `supaschema.config.json` before the first diff. Do not generate from the installer's guessed first candidate; `config validate`, `doctor`, and zero-source `diff` block until all three fields are explicit, and the PostToolUse hook must skip auto-diff until all three fields are explicit.
1616
- `supaschema.config.json` owns four workflow decisions. Schema tree fields are `schemaPaths`, `sources.to`, and `migrationsDir`; `dir:` sources read nested `.sql` files recursively, and install writes `sources.to: "dir:<schemaPaths[0]>"`. Diff baseline fields are `sources.from` and `sources.to`; `sources.from: "auto"` resolves valid `git:HEAD`, then a database URL, then `empty:` for a first migration in a fresh repository. Generated contract fields are `typesFile`, `zodFile`, `workflow.type_generation`, `workflow.zod_generation`, and `workflow.type_usage`; defaults create or refresh TypeScript and Zod outputs after `diff` and tell agents to use generated Zod validators at runtime boundaries. Apply policy fields are `workflow.migration_sync` and `sync.targets`; default `workflow.migration_sync: "auto"` keeps bare `supaschema sync` apply-capable, while `sync.targets.<name>.mode` decides selected targets and remote targets require approval variables. `adapter: "auto"` is provider-neutral and is not a Supabase switch. Provider-specific behavior is expressed through paths, managed schemas, transaction mode, excluded grant roles, sync targets, and explicit verify flags. Generic PostgreSQL installs use `managedSchemas: []` and reuse detected existing database URL environment variable names in `sync.targets` when present; Supabase installs seed the Supabase platform schema list and use the Supabase CLI runner by default.
1717
- Schema intent changes only in the configured declarative SQL tree (`schemaPaths` in `supaschema.config.json`), such as `database/schemas/**`, `supabase/schemas/**`, `neon/schemas/**`, `aws-postgresql/schemas/**`, `cloud-sql/schemas/**`, `alloydb/schemas/**`, or `azure-postgresql/schemas/**`. Render the migration with `supaschema diff`; do not hand-author migration SQL for changes the tree can express.

.claude/skills/supaschema/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ When the bundled PostToolUse hook is wired (`.claude/settings.json` / `.codex/ho
1313

1414
## Installed Setup
1515

16-
The normal consumer setup is package install plus one explicit setup command through the consuming project's package manager. Read `.agents/prompts/supaschema-install.md` before installing, initializing, inspecting, or explaining setup. That prompt owns package-manager detection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. Treat `supaschema.config.json`, installed schema/migration directories, Claude/Codex rule and skill files, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addenda as the package-owned setup surface. Run `supaschema init` through the matching local runner from the schema-owning package directory after install; it is idempotent and uses the package scaffold to refresh managed setup surfaces. The package scaffold installs the full supaschema skill directories directly into `.agents/skills/supaschema` and `.claude/skills/supaschema`; it does not invoke `npx skills`.
16+
The normal consumer setup is package install plus one explicit setup command through the consuming project's package manager. Read `.agents/prompts/supaschema-install.md` before installing, initializing, inspecting, or explaining setup. That prompt owns package-manager detection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. Treat `supaschema.config.json`, installed schema/migration directories, Claude/Codex rule and skill files, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addenda as the package-owned setup surface. Run `supaschema init` through the matching local runner from the schema-owning package directory after install; it is idempotent, preserves existing hook entries, appends missing supaschema hook entries at the end of the relevant event array, and uses the package scaffold to refresh managed setup surfaces. The package scaffold installs the full supaschema skill directories directly into `.agents/skills/supaschema` and `.claude/skills/supaschema`; it does not invoke `npx skills`.
1717

1818
If this skill was installed through `npx skills`, treat it as portable workflow context only. Agent Skills installs `SKILL.md`-based folders into a user-selected skill location; it does not create `supaschema.config.json`, schema/migration directories, passive rule files, hook scripts, or hook registration. To install those project enforcement surfaces, install the npm package with the consuming project's manager from the owning package directory, then run `supaschema init` through the same manager's local runner from that directory. The package scaffold installs the rule and hooks; the `npx skills` lane does not.
1919

.codex/hooks.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@
2525
}
2626
],
2727
"PostToolUse": [
28+
{
29+
"matcher": "^(Bash|apply_patch|Edit|Write|edit_file)$",
30+
"hooks": [
31+
{
32+
"type": "command",
33+
"command": "node \"${CODEX_PROJECT_DIR:-$PWD}/.codex/hooks/sync-llm-on-claude-surface-change.mjs\"",
34+
"timeout": 130,
35+
"statusMessage": "Syncing Claude agent surfaces after edits"
36+
}
37+
]
38+
},
2839
{
2940
"matcher": "^(apply_patch|Edit|Write|edit_file)$",
3041
"hooks": [

.codex/hooks/general-guard.mjs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@ import { fileURLToPath } from "node:url";
44

55
import { evaluateBashPolicy } from "./guards/bash-policy-checks.mjs";
66

7-
export function evaluateGeneralGuardHook({ payload = {}, env = process.env } = {}) {
7+
export function evaluateGeneralGuardHook({
8+
payload = {},
9+
env = process.env,
10+
} = {}) {
811
if ((payload?.hook_event_name ?? "PreToolUse") !== "PreToolUse") {
912
return {};
1013
}
11-
const toolName = String(payload?.tool_name ?? "");
12-
if (!["Bash", "exec_command", "functions.exec_command"].includes(toolName)) {
14+
if (
15+
!["Bash", "exec_command", "functions.exec_command"].includes(
16+
String(payload?.tool_name ?? "")
17+
)
18+
) {
1319
return {};
1420
}
21+
1522
const result = evaluateBashPolicy(payload, env);
16-
return result.action === "block" ? deny(result.message) : {};
23+
if (result.action !== "block") {
24+
return {};
25+
}
26+
27+
return deny(result.message);
1728
}
1829

1930
function deny(reason) {
@@ -39,10 +50,13 @@ function runtimeErrorResult(error) {
3950
}
4051

4152
async function main() {
53+
let payload = {};
4254
try {
4355
const raw = readFileSync(0, "utf8");
44-
const payload = raw.trim() ? JSON.parse(raw) : {};
45-
process.stdout.write(`${JSON.stringify(evaluateGeneralGuardHook({ payload }))}\n`);
56+
payload = raw.trim() ? JSON.parse(raw) : {};
57+
process.stdout.write(
58+
`${JSON.stringify(evaluateGeneralGuardHook({ payload }))}\n`
59+
);
4660
} catch (error) {
4761
process.stdout.write(`${JSON.stringify(runtimeErrorResult(error))}\n`);
4862
}

.codex/rules/supaschema.rules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# ## Rules
1616
#
1717
# - Consumer migration policy must rely on project files, generated hook context, and supaschema command output. Repo-local maintainer tooling such as Code Atlas, cclsp, FastMCP, and context-enforcement hooks is not part of the published consumer install surface.
18-
# - Consumer setup is package install plus one explicit setup command with the consuming project's package manager. The agent install protocol lives at `.agents/prompts/supaschema-install.md`; it owns package-manager selection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. The installed config, schema/migration directories, supaschema consumer rule/skill/hook bundle, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addendum are part of the package setup surface. Maintainer-only Claude/Codex optimization and context-enforcement tooling remains repo-local under Rule 13. `supaschema init` performs consumer setup through the shared scaffolder (`bin/scaffold.mjs`) — config, directories, agent bundle, hook wiring, and pending path-confirmation state when needed. Run it through the matching local runner from the schema-owning package directory after install. It is idempotent: existing JSON config files are left untouched unless explicit repair is requested, JavaScript config files are not loaded or converted, and the managed guidance block is upserted in place.
18+
# - Consumer setup is package install plus one explicit setup command with the consuming project's package manager. The agent install protocol lives at `.agents/prompts/supaschema-install.md`; it owns package-manager selection, workspace targeting, local runner commands, setup commands, and wrong-manager stop conditions. The installed config, schema/migration directories, supaschema consumer rule/skill/hook bundle, hook wiring, and tagged `AGENTS.md` / `CLAUDE.md` addendum are part of the package setup surface. Maintainer-only Claude/Codex optimization and context-enforcement tooling remains repo-local under Rule 13. `supaschema init` performs consumer setup through the shared scaffolder (`bin/scaffold.mjs`) — config, directories, agent bundle, hook wiring, and pending path-confirmation state when needed. Run it through the matching local runner from the schema-owning package directory after install. It is idempotent: existing JSON config files are left untouched unless explicit repair is requested, JavaScript config files are not loaded or converted, and the managed guidance block is upserted in place. Hook wiring preserves existing entries and appends missing supaschema hook entries at the end of the relevant event array; it only removes the known broken package-owned Claude script entries that passed `${CLAUDE_PROJECT_DIR}` script paths through `args`.
1919
# - Normal resolved installs do not create `.supaschema/`. If `.supaschema/install.json` exists and records `"pathConfirmationNeeded": true`, inspect the detected candidates, ask the user which `schemaPaths`, `sources.to`, and `migrationsDir` to use, and update `supaschema.config.json` before the first diff. Do not generate from the installer's guessed first candidate; `config validate`, `doctor`, and zero-source `diff` block until all three fields are explicit, and the PostToolUse hook must skip auto-diff until all three fields are explicit.
2020
# - `supaschema.config.json` owns four workflow decisions. Schema tree fields are `schemaPaths`, `sources.to`, and `migrationsDir`; `dir:` sources read nested `.sql` files recursively, and install writes `sources.to: "dir:<schemaPaths[0]>"`. Diff baseline fields are `sources.from` and `sources.to`; `sources.from: "auto"` resolves valid `git:HEAD`, then a database URL, then `empty:` for a first migration in a fresh repository. Generated contract fields are `typesFile`, `zodFile`, `workflow.type_generation`, `workflow.zod_generation`, and `workflow.type_usage`; defaults create or refresh TypeScript and Zod outputs after `diff` and tell agents to use generated Zod validators at runtime boundaries. Apply policy fields are `workflow.migration_sync` and `sync.targets`; default `workflow.migration_sync: "auto"` keeps bare `supaschema sync` apply-capable, while `sync.targets.<name>.mode` decides selected targets and remote targets require approval variables. `adapter: "auto"` is provider-neutral and is not a Supabase switch. Provider-specific behavior is expressed through paths, managed schemas, transaction mode, excluded grant roles, sync targets, and explicit verify flags. Generic PostgreSQL installs use `managedSchemas: []` and reuse detected existing database URL environment variable names in `sync.targets` when present; Supabase installs seed the Supabase platform schema list and use the Supabase CLI runner by default.
2121
# - Schema intent changes only in the configured declarative SQL tree (`schemaPaths` in `supaschema.config.json`), such as `database/schemas/**`, `supabase/schemas/**`, `neon/schemas/**`, `aws-postgresql/schemas/**`, `cloud-sql/schemas/**`, `alloydb/schemas/**`, or `azure-postgresql/schemas/**`. Render the migration with `supaschema diff`; do not hand-author migration SQL for changes the tree can express.

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,45 @@ services/license-worker/
3636
scripts/agent-hooks/
3737
scripts/code-atlas/
3838
scripts/stripe/
39+
.agents/*
40+
!.agents/prompts/
41+
.agents/prompts/*
42+
!.agents/prompts/supaschema-install.md
43+
!.agents/skills/
44+
.agents/skills/*
45+
!.agents/skills/supaschema/
46+
!.agents/skills/supaschema/**
47+
.claude/*
3948
.claude/agents/
4049
.claude/cclsp.json
50+
!.claude/hooks/
51+
.claude/hooks/*
52+
!.claude/hooks/guards/
53+
.claude/hooks/guards/*
54+
!.claude/hooks/guards/bash-policy-checks.mjs
55+
!.claude/hooks/sync-llm-on-claude-surface-change.mjs
56+
!.claude/rules/
57+
.claude/rules/*
58+
!.claude/rules/supaschema.md
4159
.claude/settings.json
60+
!.claude/skills/
61+
.claude/skills/*
62+
!.claude/skills/supaschema/
63+
!.claude/skills/supaschema/**
64+
.codex/*
4265
.codex/agents/
4366
.codex/config.toml
67+
!.codex/hooks.json
68+
!.codex/hooks/
69+
.codex/hooks/*
70+
!.codex/hooks/guards/
71+
.codex/hooks/guards/*
72+
!.codex/hooks/guards/bash-policy-checks.mjs
73+
!.codex/hooks/general-guard.mjs
74+
!.codex/hooks/sync-llm-on-claude-surface-change.mjs
75+
!.codex/rules/
76+
.codex/rules/*
77+
!.codex/rules/supaschema.rules
4478
wrangler.toml
4579
cloudflare/
4680
pyproject.toml

0 commit comments

Comments
 (0)