create-flowdular 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/agent-template/.agents/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.agents/skills/bug-hunt/SKILL.md +1 -1
- package/agent-template/.agents/skills/spec-interview/SKILL.md +20 -20
- package/agent-template/.agents/skills/ux-design/SKILL.md +1 -1
- package/agent-template/.ai/README.md +5 -3
- package/agent-template/.ai/agents/README.md +1 -1
- package/agent-template/.ai/agents/sandbox/agentic-engineer.md +1 -0
- package/agent-template/.ai/agents/sandbox/backend-engineer.md +1 -0
- package/agent-template/.ai/agents/sandbox/frontend-engineer.md +1 -0
- package/agent-template/.ai/blueprints/add-migration/README.md +1 -1
- package/agent-template/.ai/examples/bad/client-imports-server/README.md +1 -1
- package/agent-template/.ai/examples/bad/missing-acl/README.md +1 -1
- package/agent-template/.ai/examples/bad/tenant-from-body/README.md +1 -1
- package/agent-template/.ai/guides/application-development.md +7 -5
- package/agent-template/.ai/platform-capabilities.md +2 -0
- package/agent-template/.ai/policies/task-budgets.yaml +1 -1
- package/agent-template/.ai/rules/flowdular.md +3 -2
- package/agent-template/.ai/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.ai/skills/bug-hunt/SKILL.md +1 -1
- package/agent-template/.ai/skills/spec-interview/SKILL.md +20 -20
- package/agent-template/.ai/skills/ux-design/SKILL.md +1 -1
- package/agent-template/.ai/subagents/module-executor.md +25 -0
- package/agent-template/.ai/subagents/reviewer.md +23 -0
- package/agent-template/.ai/subagents/spec-author.md +23 -0
- package/agent-template/.claude/agents/module-executor.md +22 -0
- package/agent-template/.claude/agents/reviewer.md +24 -0
- package/agent-template/.claude/agents/spec-author.md +20 -0
- package/agent-template/.claude/skills/auth-security-review/SKILL.md +1 -1
- package/agent-template/.claude/skills/bug-hunt/SKILL.md +1 -1
- package/agent-template/.claude/skills/spec-interview/SKILL.md +20 -20
- package/agent-template/.claude/skills/ux-design/SKILL.md +1 -1
- package/agent-template/.codex/agents/module-executor.toml +17 -0
- package/agent-template/.codex/agents/reviewer.toml +14 -0
- package/agent-template/.codex/agents/spec-author.toml +15 -0
- package/agent-template/AGENTS.md +3 -2
- package/agent-template/CLAUDE.md +3 -2
- package/agent-template/docs/configuration.md +27 -0
- package/agent-template/docs/design-system.md +2 -2
- package/agent-template/docs/modules.md +6 -0
- package/agent-template/docs/sandbox.md +117 -6
- package/agent-template/rulesync.jsonc +1 -1
- package/dist/bin.js +9 -0
- package/package.json +2 -2
- package/template/default/.env.example +7 -0
- package/template/default/.prettierignore +2 -0
- package/template/default/README.md +6 -4
- package/template/default/modules/example/package.json +1 -1
- package/template/default/package.json +3 -2
- package/template/default/platform/index.html +7 -19
- package/template/default/platform/package.json +1 -1
- package/template/default/platform/public/favicon.svg +1 -1
- package/template/default/platform/src/App.tsrx +25 -1
- package/template/default/platform/src/generated/modules.server.ts +2 -0
package/README.md
CHANGED
|
@@ -50,12 +50,15 @@ The generator installs dependencies and initializes Git by default. Local develo
|
|
|
50
50
|
|
|
51
51
|
## Ready for coding agents
|
|
52
52
|
|
|
53
|
-
Every app includes `.ai` rules, skills, role prompts, blueprints,
|
|
54
|
-
reference examples, plus `AGENTS.md`, `CLAUDE.md`, `.agents/skills
|
|
55
|
-
`.claude/skills
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
Every app includes `.ai` rules, skills, role prompts, subagents, blueprints,
|
|
54
|
+
policies and reference examples, plus `AGENTS.md`, `CLAUDE.md`, `.agents/skills`,
|
|
55
|
+
`.claude/skills` and the spec author, module executor and reviewer as subagents in
|
|
56
|
+
`.claude/agents` and `.codex/agents`. The chat-first sandbox is installed with the
|
|
57
|
+
app, so `pnpm sandbox` starts it without a download. These files are bundled with
|
|
58
|
+
the generator and are available with `--no-install`. Personal agent settings and
|
|
59
|
+
credentials are never copied.
|
|
60
|
+
|
|
61
|
+
Edit `.ai/rules`, `.ai/skills` or `.ai/subagents`, then run `pnpm rules:generate`. `pnpm verify`
|
|
59
62
|
checks that the generated instructions are in sync. The instructions explain
|
|
60
63
|
where to find the installed SDK and how to extend the application's modules.
|
|
61
64
|
|
|
@@ -74,7 +74,7 @@ Report each finding as: severity (`blocker`, `should-fix`, `taste`), claim, `fil
|
|
|
74
74
|
```text
|
|
75
75
|
blocker Tenant id read from body modules/inventory/src/api/endpoints.ts:41
|
|
76
76
|
A member of tenant A posts { tenantId: "B" } and creates a location in B.
|
|
77
|
-
AGENTS.md
|
|
77
|
+
AGENTS.md 4. Fix: principalFromContext(octane)!.tenantId; drop the field.
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
## 8. Known platform gaps to keep in mind (not module defects)
|
|
@@ -29,7 +29,7 @@ description: >-
|
|
|
29
29
|
| View falls back to the dashboard | `ApplicationShell.tsrx` renders `overview` for a view id that no visible navigation or account menu entry reaches |
|
|
30
30
|
| Icon renders as a grid | `glyph` or `Icon name` is not an `ICON_PATHS` key (`packages/ui/src/icons/Icon.tsrx` falls back to `modules`) |
|
|
31
31
|
| Stale data after a change | each component owns a store instance (`useMemo(() => createXClientState(), [])`); check the `store.act` that should have written it. `store.commits(cb)` and `store.stats()` from `segment-state` show what was committed |
|
|
32
|
-
| Schema error on start | `
|
|
32
|
+
| Schema error on start | `runDatabaseMigrations`: `CHECKSUM_MISMATCH` means applied SQL bytes changed; `PARTIAL_MIGRATION` means only part of a pending migration exists. Never delete or bypass the database to hide either condition; restore the shipped bytes or diagnose the partial schema |
|
|
33
33
|
|
|
34
34
|
## 2b. Reproduction snippets
|
|
35
35
|
|
|
@@ -23,26 +23,26 @@ For an edit, also read the module's current `spec/module.yaml` and write the sma
|
|
|
23
23
|
|
|
24
24
|
One pass, in this order. For each row, write the default from the card into the spec and record it as a `decisions[]` entry with `decidedBy: default`. Ask only where the answer is a business fact that no default can supply.
|
|
25
25
|
|
|
26
|
-
| Decision | Default to propose
|
|
27
|
-
| ---------------------- |
|
|
28
|
-
| Actors | Owner manages, member reads
|
|
29
|
-
| Entities and fields | One primary entity; `name` required, `maxLength` 120; no field the request did not name
|
|
30
|
-
| Uniqueness | The human-facing code is `unique: tenant`; everything else `none`
|
|
31
|
-
| States and transitions | `active` and `archived`, every transition behind the manage permission
|
|
32
|
-
| Who sees what | Both permissions in the same navigation entry; the manage action hidden without the scope
|
|
33
|
-
| What is denied | Unauthenticated 401, missing permission 403, cross-tenant read returns nothing
|
|
34
|
-
| Failure behaviour | A duplicate returns a stable conflict and changes nothing; bounds return 400
|
|
35
|
-
| Cross-module reads | None. A read of another module goes through its public capability and a declared dependency
|
|
36
|
-
| Screens | One `list` screen with the entity's identifying columns
|
|
37
|
-
| Widgets | None. A count belongs on `dashboard.metrics` only when the request asks for it
|
|
38
|
-
| Settings | None. A number the business may change later is `scope: tenant` with a stated default
|
|
39
|
-
| Feature flags | Ask for one whenever a change alters behaviour a workspace already relies on, or is hard to undo: `kind: flag`, boolean, `scope: tenant`, a stated default, and the behaviour named in an invariant
|
|
40
|
-
| Agent tools | None. A tool is a later phase and `risk` may only be `read` or `workspace-write`
|
|
41
|
-
| Outside sources | None. A named public source is `research`, with the entity its findings attach to
|
|
42
|
-
| Other systems | None. A named system is one `source` adapter per record kind, run on demand
|
|
43
|
-
| Documents | None. A named document is one `templates[]` entry on the record it describes
|
|
44
|
-
| Reports |
|
|
45
|
-
| Out of scope | Every item from the card's gap list the request touched, each with its business decision
|
|
26
|
+
| Decision | Default to propose | Lands in |
|
|
27
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
|
|
28
|
+
| Actors | Owner manages, member reads | `permissions`, `invariants` |
|
|
29
|
+
| Entities and fields | One primary entity; `name` required, `maxLength` 120; no field the request did not name | `entities[]` |
|
|
30
|
+
| Uniqueness | The human-facing code is `unique: tenant`; everything else `none` | `entities[].fields[].unique` |
|
|
31
|
+
| States and transitions | `active` and `archived`, every transition behind the manage permission | `entities[].states` |
|
|
32
|
+
| Who sees what | Both permissions in the same navigation entry; the manage action hidden without the scope | `permissions`, `screens[]`, `invariants` |
|
|
33
|
+
| What is denied | Unauthenticated 401, missing permission 403, cross-tenant read returns nothing | `acceptanceScenarios` |
|
|
34
|
+
| Failure behaviour | A duplicate returns a stable conflict and changes nothing; bounds return 400 | `invariants`, `acceptanceScenarios` |
|
|
35
|
+
| Cross-module reads | None. A read of another module goes through its public capability and a declared dependency | `dependencies`, `dataOwnership` |
|
|
36
|
+
| Screens | One `list` screen with the entity's identifying columns | `screens[]` |
|
|
37
|
+
| Widgets | None. A count belongs on `dashboard.metrics` only when the request asks for it | `widgets[]` |
|
|
38
|
+
| Settings | None. A number the business may change later is `scope: tenant` with a stated default | `settings[]` |
|
|
39
|
+
| Feature flags | Ask for one whenever a change alters behaviour a workspace already relies on, or is hard to undo: `kind: flag`, boolean, `scope: tenant`, a stated default, and the behaviour named in an invariant | `settings[]` |
|
|
40
|
+
| Agent tools | None. A tool is a later phase and `risk` may only be `read` or `workspace-write` | `agentTools[]` |
|
|
41
|
+
| Outside sources | None. A named public source is `research`, with the entity its findings attach to | `research` |
|
|
42
|
+
| Other systems | None. A named system is one `source` adapter per record kind, run on demand | `adapters[]` |
|
|
43
|
+
| Documents | None. A named document is one `templates[]` entry on the record it describes | `templates[]` |
|
|
44
|
+
| Reports | A named report is one provider on `reports.v1` returning tiles and series; a named list export is one `defineListExport`; named records are findable through `search.providers.v1`. None of the three has a specification key, so each needs a decision naming the screen or the `actions[]` entry that registers it | `actions[]`, `invariants` |
|
|
45
|
+
| Out of scope | Every item from the card's gap list the request touched, each with its business decision | `outOfScope[]`, `decisions[]` |
|
|
46
46
|
|
|
47
47
|
A default you propose is still a decision: it goes into `decisions[]` so the operator can see and overturn it, and so the next agent never re-derives it.
|
|
48
48
|
|
|
@@ -81,7 +81,7 @@ Read-only master-detail (runs, playground) keeps `ui-two-col` (+ `--wide-aside`)
|
|
|
81
81
|
- `Alert`: `tone` danger (default), warning, info.
|
|
82
82
|
- `Avatar`: `name`, `square` (organizations), `large`.
|
|
83
83
|
- `Icon`: `name`, `size` (18 default, 16 in controls, 14 in `Button size="sm"`), `strokeWidth`.
|
|
84
|
-
- `BrandMark`: `size`, `
|
|
84
|
+
- `BrandMark`: `size`, `tone`; three bars with a copper accent bar, brand moments only.
|
|
85
85
|
|
|
86
86
|
Icon keys (`ICON_PATHS`, `packages/ui/src/icons/Icon.tsrx`): `dashboard`, `parties`, `catalog`, `user`, `users`, `shield`, `code`, `modules`, `file-text`, `play`, `bot`, `flask`, `activity`, `plug`, `search`, `chevron-down`, `chevron-left`, `chevron-right`, `chevrons-up-down`, `sort`, `calendar`, `plus`, `panel-left`, `check`, `filter`, `download`, `more`, `external`, `alert`, `x`, `sign-out`, `refresh`, `help`, `info`, `key`, `settings`, `braces`, `copy`. An unknown name renders `modules` silently, so check the list.
|
|
87
87
|
|
|
@@ -10,6 +10,7 @@ Flowdular is an agentic foundation framework. The platform under `packages/`, `m
|
|
|
10
10
|
| `rules/*.md` | Canonical cross-agent instructions. RuleSync generates the root `AGENTS.md` and `CLAUDE.md` from these files; `pnpm rules:check` rejects drift. |
|
|
11
11
|
| `agents/sandbox/*.md` | Loaded at sandbox start by `packages/coding-agent/src/roles/registry.ts` (`loadAgentRoles`); `gates`, `handoff` and `allowedPaths` are enforced. `dependencies` always runs, a `HANDOFF:` line must name a role from the list and never the role itself, and writes outside the active role allowlist are quarantined and restored before validation. Defaults in `packages/coding-agent/src/roles/defaults.ts` are regenerated from these files by `pnpm --filter @flowdular/coding-agent sync-roles`, and `tests/sync.test.ts` fails when they drift. |
|
|
12
12
|
| `agents/{module-executor,reviewer,spec-author}.md` | Read by people and coding tools at the repository root; named in `blueprints/*/blueprint.json`. Not loaded by code. |
|
|
13
|
+
| `subagents/*.md` | The same three root roles as delegable subagents. RuleSync generates `.claude/agents/<name>.md` and `.codex/agents/<name>.toml` from them, so Claude Code and Codex can hand a phase to the role; each body points at its `agents/<id>.md` prompt and its one task skill. |
|
|
13
14
|
| `skills/*/SKILL.md` | Canonical cross-agent procedures. They are copied into every sandbox session as `reference/skills/` (`packages/sandbox/src/server/reference.ts`) and RuleSync generates the discovery copies under `.agents/skills` and `.claude/skills`. |
|
|
14
15
|
| `blueprints/*/blueprint.json` | `pnpm flowdular blueprint list` and `blueprint validate --all` (`packages/cli/src/runner.ts`, discovery in `packages/cli/src/validation.ts` `findNamedFiles`) validate every `blueprint.json` against `packages/contracts/schemas/blueprint.schema.json` and check the companion files exist; `pnpm validate` runs it in CI. The sandbox labels sessions `new-module@1.0.0` and `edit-module@1.0.0`. |
|
|
15
16
|
| `blueprints/*/*.yaml`, `*.schema.json`, `examples/` | Existence-checked by `validateBlueprint`; otherwise documentation for agents and reviewers. Nothing executes `steps.yaml` or `gates.yaml`. |
|
|
@@ -17,7 +18,7 @@ Flowdular is an agentic foundation framework. The platform under `packages/`, `m
|
|
|
17
18
|
| `policies/task-budgets.yaml`, `policies/path-ownership.yaml` | Read by the `git-pr` delivery target (`packages/sandbox/src/server/delivery/policies.ts`): the changed-file and new-dependency budget per session kind, and path owners plus `crossOwnerChanges.requireReviewer` for the pull request body. Review guidance otherwise. |
|
|
18
19
|
| `examples/**` | Reference shapes for agents; not compiled or tested. |
|
|
19
20
|
|
|
20
|
-
`AGENTS.md` and `docs/design-system.md` are copied into each session's `reference/` as well (`packages/sandbox/src/server/reference.ts`). `AGENTS.md`, `CLAUDE.md`, `.agents/skills` and `.
|
|
21
|
+
`AGENTS.md` and `docs/design-system.md` are copied into each session's `reference/` as well (`packages/sandbox/src/server/reference.ts`). `AGENTS.md`, `CLAUDE.md`, `.agents/skills`, `.claude/skills`, `.claude/agents` and `.codex/agents` are generated compatibility outputs. Edit `.ai/rules`, `.ai/skills` or `.ai/subagents`, then run `pnpm rules:generate`.
|
|
21
22
|
|
|
22
23
|
## Using the skills from your own tool
|
|
23
24
|
|
|
@@ -27,8 +28,8 @@ sandbox turn receives one Task skill from `packages/coding-agent/src/roles/skill
|
|
|
27
28
|
not the entire catalog. Character-budget and routing tests guard against prompt
|
|
28
29
|
growth; characters are a stable size proxy, not a tokenizer-specific cost estimate.
|
|
29
30
|
|
|
30
|
-
- Claude Code reads the generated `CLAUDE.md` and discovers the generated `.claude/skills` copies.
|
|
31
|
-
- Codex reads the generated `AGENTS.md` and discovers the generated `.agents/skills` copies.
|
|
31
|
+
- Claude Code reads the generated `CLAUDE.md` and discovers the generated `.claude/skills` copies and the `.claude/agents` subagents.
|
|
32
|
+
- Codex reads the generated `AGENTS.md` and discovers the generated `.agents/skills` copies and the `.codex/agents` subagents.
|
|
32
33
|
- Any other tool: paste `AGENTS.md` and the skill into the instruction.
|
|
33
34
|
|
|
34
35
|
Both paths land the same way: gates, then `pnpm flowdular module enable <id> --apply` for a new module (it grants the module's scopes as its last step; `auth sync-scopes` re-grants later), `pnpm verify`, pull request (`skills/release-eject-pr`). A sandbox session is a pnpm workspace of its own with the draft modules as projects, so declared dependencies resolve for real and the `dependencies` gate runs after every turn.
|
|
@@ -39,6 +40,7 @@ Both paths land the same way: gates, then `pnpm flowdular module enable <id> --a
|
|
|
39
40
|
- Skill: edit `skills/<kebab-name>/SKILL.md` with `name`, `description`, `roles`, `when`; keep it focused, verify API claims against the cited code, add a row in `skills/README.md`, then run `pnpm rules:generate`.
|
|
40
41
|
- Blueprint: a directory under `blueprints/` with `blueprint.json` valid against `packages/contracts/schemas/blueprint.schema.json` plus `README.md`, `input.schema.json`, `plan.schema.json`, `spec-requirements.yaml`, `allowed-paths.yaml`, `required-files.yaml`, `steps.yaml`, `gates.yaml` (all required by `validateBlueprint`), and `examples/valid`, `examples/invalid` (`input*.json` validate against `input.schema.json`, `plan*.json` against `plan.schema.json`). `agentRoles` use the role ids from `agents/`; `executorProfiles` use the profile ids in `policies/model-routing.yaml`; gate ids for module blueprints come from `packages/sandbox/src/server/gates.ts`.
|
|
41
42
|
- Sandbox role: `agents/sandbox/<id>.md` with the front matter `id`, `name`, `purpose`, `allowedPaths`, `gates`, `handoff` (see `agents/README.md`), then regenerate the bundled defaults: `pnpm --filter @flowdular/coding-agent sync-roles` (the script provided by `packages/coding-agent`; it rewrites `src/roles/defaults.ts` from these files) and run `pnpm --filter @flowdular/coding-agent test`.
|
|
43
|
+
- Root subagent: `subagents/<name>.md` with the front matter `name`, `targets`, `description` and an optional `claudecode` block, a body that names the `agents/<id>.md` prompt and the one task skill, then `pnpm rules:generate`. Keep the procedure in the role prompt; the subagent file stays a pointer so the two cannot drift.
|
|
42
44
|
- Policy: keep it truthful about what code enforces; name the file that does.
|
|
43
45
|
|
|
44
46
|
Formatting: `npx prettier --write .ai docs`, then `pnpm rules:generate`. No em or en dashes anywhere.
|
|
@@ -17,7 +17,7 @@ The five roles and who takes the first turn: `business-manager` for both a new m
|
|
|
17
17
|
|
|
18
18
|
## Root roles run at the repository root
|
|
19
19
|
|
|
20
|
-
`module-executor.md`, `reviewer.md`, `spec-author.md` describe the same jobs for an agent working in a checkout with a shell (Claude Code, Codex, a person). No code loads them; `.ai/blueprints/*/blueprint.json` names them in `agentRoles` and `requiredReviewers`. Their `allowedPaths` are relative to the repository root and they run the gates themselves with the commands listed in each blueprint's `gates.yaml`.
|
|
20
|
+
`module-executor.md`, `reviewer.md`, `spec-author.md` describe the same jobs for an agent working in a checkout with a shell (Claude Code, Codex, a person). No code loads them; `.ai/blueprints/*/blueprint.json` names them in `agentRoles` and `requiredReviewers`, and `.ai/subagents/<id>.md` exposes each one as a delegable subagent that points back here (RuleSync writes `.claude/agents` and `.codex/agents`). Their `allowedPaths` are relative to the repository root and they run the gates themselves with the commands listed in each blueprint's `gates.yaml`.
|
|
21
21
|
|
|
22
22
|
## Adding or changing a role
|
|
23
23
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# add-migration
|
|
2
2
|
|
|
3
|
-
Add a table, column, index or constraint through the numbered migration runner. The `.up.sql` file is the source, `src/services/migration.ts` mirrors it byte for byte, the repository calls `
|
|
3
|
+
Add a table, column, index or constraint through the numbered migration runner. The `.up.sql` file is the source, `src/services/migration.ts` mirrors it byte for byte, the repository calls `runDatabaseMigrations`, and the per-database ledger records its checksum. Existing databases adopt complete pre-ledger schema without replaying it. Procedure: `.ai/skills/migration-authoring/SKILL.md`.
|
|
4
4
|
|
|
5
5
|
Additive only. A destructive change (drop, type change, tightened check) is refused by this blueprint's input schema and needs an operator decision.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`api.ts` sits under `src/client` and imports `../services/database-repository.ts`, which pulls in `@flowdular/sdk/database` and its `node:fs`, `node:path` and `node:async_hooks` imports. The Vite client build fails on the Node built-ins, and even where it compiled the browser would hold a database handle and a `tenantId` parameter chosen by the caller, bypassing every endpoint check.
|
|
4
4
|
|
|
5
|
-
Violated rules: `AGENTS.md`
|
|
5
|
+
Violated rules: `AGENTS.md` 3 and 4 (data reaches the client only through an endpoint that resolves identity and takes the tenant from the principal) and the layering in `.ai/skills/core-extend/SKILL.md` (client code imports `@flowdular/sdk/client`, `@flowdular/sdk/ui`, `octane`, `segment-state`, and the module's own `src/client` and `src/domain` types; never `src/services` or `src/server`).
|
|
6
6
|
|
|
7
7
|
Repair with the `bug-fix` blueprint: replace the import with a `fetch` in `src/client/api.ts` as in `.ai/references/catalog/src/client/api.ts`:
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`endpoints.ts` mounts `/api/customers` with `new ServerRoute` from `@octanejs/app-core`. Nothing resolves an identity, nothing checks a permission, and `listAll()` has no tenant. Anyone who can reach the server reads every tenant's customers.
|
|
4
4
|
|
|
5
|
-
Violated rules: `AGENTS.md`
|
|
5
|
+
Violated rules: `AGENTS.md` 3 (every endpoint is `defineEndpoint` with `access: { kind: 'permission' }` and `resolveIdentity: endpointIdentityFromContext`) and 4 (tenant id from the principal). The security skill's first grep (`grep -rn "new ServerRoute" modules/*/src | grep -v modules/auth`) finds it.
|
|
6
6
|
|
|
7
7
|
Repair with the `bug-fix` blueprint (or `edit-module`, change class `endpoint`):
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`endpoints.ts` has a permission and an identity resolver, and still lets a member of tenant A create a customer in tenant B by posting `{ "tenantId": "B", "name": "..." }`. The permission check passes because the principal holds `customers.records.manage` in its own tenant; the body decides where the row lands. The mutation also skips `sessionMutationDenial`, so a cross-site form post with a valid cookie would be accepted.
|
|
4
4
|
|
|
5
|
-
Violated rules: `AGENTS.md`
|
|
5
|
+
Violated rules: `AGENTS.md` 4 (tenant id only from `principalFromContext(octane)!.tenantId`) and 3 (an explicit permission and an identity resolver on every endpoint). The security skill's grep `grep -rn tenantId modules/*/src/api | grep -v principalFromContext` finds it.
|
|
6
6
|
|
|
7
7
|
Repair with the `bug-fix` blueprint: remove the body field, take `auth: AuthRuntime` in `createCustomerRoutes`, and write
|
|
8
8
|
|
|
@@ -84,11 +84,13 @@ spec approval or production access.
|
|
|
84
84
|
|
|
85
85
|
## Maintain the agent guidance
|
|
86
86
|
|
|
87
|
-
Edit `.ai/rules` and `.ai/
|
|
88
|
-
`pnpm rules:check`. Codex reads `AGENTS.md
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
Edit `.ai/rules`, `.ai/skills` and `.ai/subagents`, then run `pnpm rules:generate`
|
|
88
|
+
and `pnpm rules:check`. Codex reads `AGENTS.md`, `.agents/skills` and
|
|
89
|
+
`.codex/agents`; Claude Code reads `CLAUDE.md`, `.claude/skills` and
|
|
90
|
+
`.claude/agents`. Keep generated copies synchronized. `.ai/agents` contains
|
|
91
|
+
reusable role instructions, and `.ai/subagents` exposes the root roles as
|
|
92
|
+
delegable subagents; `.ai/blueprints` and `.ai/policies` are project-local inputs
|
|
93
|
+
referenced by `flowdular.json`.
|
|
92
94
|
|
|
93
95
|
Split a skill when it contains independent procedures with different owning
|
|
94
96
|
files, write scopes or verification commands. Keep shared requirements in the
|
|
@@ -28,6 +28,8 @@ Read this file before writing or implementing a spec. It replaces scanning `modu
|
|
|
28
28
|
|
|
29
29
|
**Feature flags.** A flag is a module setting declared `kind: 'flag'`: a non-secret `boolean` with a `defaultValue`, a `label`, a `description` and `scope: 'tenant'`, which is the default and the only scope a flag may take; `defineModuleSettings` refuses anything else, a platform-scoped flag included. There is no flag store, no flag endpoint and no flag registry. A module reads one on the request path with the ordinary settings read, `context.settings.get<boolean>(tenantId, moduleId, key)`: a lookup of the declaration, a lookup of the cached per `(tenant, module)` value set under a key the read builds, the touch that keeps that entry at the head of the cache, the property read and one `typeof` check. No query of its own, and nothing beyond what any setting already costs: a declared `pattern` is compiled once with the declaration, never per read. There is deliberately no `context.flags`; the read is the settings read, and the module id is the one the module already knows. An override is per workspace behind `system.settings.manage` on the Flags tab of Administration, Modules, which groups every declared flag by its owning module and links the audit trail. Every change appends one `settings.flag.changed` auth audit event with the module, the key, the previous and next values and the actor (`settings.updated` stays the event for every other setting). No percentage rollout and no targeting: a flag is on or off for a workspace. A specification declares one as a `settings[]` entry with `kind: flag`, which `spec validate` holds to boolean, `scope: tenant` and a stated default; `research.core` ships the first one, `allowAgents`.
|
|
30
30
|
|
|
31
|
+
**Branding.** The identity one deployment is served with is seven platform-scoped `system.core` settings (`appName`, `documentTitle`, `description`, `ogImageUrl`, `faviconUrl`, `themeColor`, `logoUrl`, `modules/system/src/settings.ts`), edited by a principal with `system.settings.manage` on the Administration screen `branding` and audited like any other setting. They are one value for the whole installation, because the sign-in screen and a shared link are rendered before a workspace is known. The application route resolves them once per request through the provider `system.core` installs with `installApplicationBranding` (`packages/server/src/application-branding.ts`), hands the server render page state and the browser one JSON data block, and the client reads both with `configureBrandingFromPage` plus `applicationBranding` (`packages/client/src/branding.ts`); the shell wordmark, the mobile header, the sign-in screen, the boot splash, the document title, the description, the icon, the theme colour, the social image and the label an authenticator lists a TOTP enrolment under all come from that one read, so no module fetches branding and nothing disagrees. Every value is bounded by its declaration: a name carries no markup or quote, an address is a same-origin absolute path or an https URL (`javascript:`, `data:` and protocol-relative values are refused at the write), a colour is six hex digits, and a stored value that no longer fits falls back to the product's own. Every https branding image origin an operator stores is added to `img-src` of the content security policy for that deployment, so the icon, the logo and the screen's own preview load. A logo is an address, never an upload, and there is no per-workspace branding, no colour theme and no custom CSS. An application whose own entry predates this and renders none of it, or still declares a static icon or theme colour beside the rendered one, is reported by `pnpm flowdular doctor` as the `platform.branding` check.
|
|
32
|
+
|
|
31
33
|
**Module activation.** The composed module set is CLI-owned and baked at build; what an owner changes from Administration, Modules is per-workspace activation of the modules the application already composes. `system.core` keeps it in `system_module_activations` (a composed module without a row is active), lists it through `GET /api/system/modules` (every catalog row with `active`, `optional` and `dependents`) and `GET /api/system/modules/active` (the active composed ids, for any member holding `system.workspace.access`), and changes it through `POST /api/system/modules/activate` and `/api/system/modules/deactivate` behind `system.settings.manage` with CSRF first. `system.core`, `auth.core`, `users.core` and `profile.core` (`REQUIRED_MODULE_IDS` in `@flowdular/sdk/contracts`) are never deactivated; a module another active module depends on, through a declared module dependency or a required capability, is refused with 409 `MODULE_HAS_ACTIVE_DEPENDENTS` naming the dependents, a required one with 409 `MODULE_REQUIRED`, and activating a module whose dependency is inactive with 409 `MODULE_DEPENDENCY_INACTIVE`. Every change appends one `system.module.activated` or `system.module.deactivated` auth audit event. The state is one per-tenant snapshot memoised for 30 seconds and published as the public capability `system.modules.v1` (`isActive(tenantId, moduleId)`, `activeIds(tenantId)`, `modules/system/src/server/capability.ts`). Enforcement costs a module nothing: the generated composition binds every route to its module id (`bindModuleCompositions`, `packages/server/src/module-activation.ts`), `defineEndpoint` answers 403 `MODULE_INACTIVE` after the permission check for an endpoint of an inactive module in the principal's workspace (`EndpointIdentity.tenantId` comes from `endpointIdentityFromContext`), and the application shell reads the active ids before it renders and hides the navigation, views, widgets and command search of an inactive module (`contributionsForActiveModules`, `packages/client/src/shell/modules.ts`; a failed read shows everything). Not covered yet: the agent tools of an inactive module are still offered, because the harness registry has no per-tenant module hook.
|
|
32
34
|
|
|
33
35
|
**Navigation groups.** A navigation contribution picks exactly one group (`NavigationGroup`, `packages/client/src/contributions.ts`): An Administration item also names a section (`NavigationSection`: `people`, `identity`, `compliance`, `integrations`, `platform`), and the panel renders that group as five short labelled lists in that order with unsectioned items last (`navigationSections`, `packages/client/src/shell/navigation.ts`). In the sidebar a sectioned group shows one entry per section (`NAVIGATION_SECTION_ICONS`), and while a sectioned view is open a context rail beside the sidebar lists that section's screens and the workspace makes room for it (`ContextRail`, `sectionOfView`, `sectionItems`); on a phone the same screens nest under the section entry in the drawer instead.
|
|
@@ -33,7 +33,7 @@ sandbox:
|
|
|
33
33
|
messageLength: 1 to 20000 characters (packages/sandbox/src/server/turns.ts)
|
|
34
34
|
briefLength: at least 8 characters (planning.ts assertBrief)
|
|
35
35
|
gateTimeout: 5 minutes per gate, output capped at 12000 characters (gates.ts)
|
|
36
|
-
gateFailure: the same role repairs;
|
|
36
|
+
gateFailure: the same role repairs; at most maxRepairLoops consecutive repair turns per chain, then the chain returns to the operator
|
|
37
37
|
byokReads: 400 listed files, 128 KB per read (packages/coding-agent/src/drivers/byok.ts)
|
|
38
38
|
review:
|
|
39
39
|
chainedTurns: stop and read the transcript after four automatic handoffs on one brief
|
|
@@ -87,5 +87,6 @@ made in the Flowdular repository and released before this application uses it.
|
|
|
87
87
|
The skills and examples use @flowdular/sdk subpath imports. For pnpm --filter,
|
|
88
88
|
read the actual module package name from its package.json. Use pnpm verify and
|
|
89
89
|
pnpm build for this application. Root .ai files are editable project guidance;
|
|
90
|
-
run pnpm rules:generate after changing rules or
|
|
91
|
-
AGENTS.md, CLAUDE.md, .agents/skills
|
|
90
|
+
run pnpm rules:generate after changing rules, skills or subagents, then pnpm
|
|
91
|
+
rules:check. AGENTS.md, CLAUDE.md, .agents/skills, .claude/skills, .claude/agents
|
|
92
|
+
and .codex/agents are generated copies.
|
|
@@ -80,7 +80,7 @@ Report each finding as: severity (`blocker`, `should-fix`, `taste`), claim, `fil
|
|
|
80
80
|
```text
|
|
81
81
|
blocker Tenant id read from body modules/inventory/src/api/endpoints.ts:41
|
|
82
82
|
A member of tenant A posts { tenantId: "B" } and creates a location in B.
|
|
83
|
-
AGENTS.md
|
|
83
|
+
AGENTS.md 4. Fix: principalFromContext(octane)!.tenantId; drop the field.
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
## 8. Known platform gaps to keep in mind (not module defects)
|
|
@@ -35,7 +35,7 @@ when: A report, failing gate, wrong status code, blank screen, or unexpected 4xx
|
|
|
35
35
|
| View falls back to the dashboard | `ApplicationShell.tsrx` renders `overview` for a view id that no visible navigation or account menu entry reaches |
|
|
36
36
|
| Icon renders as a grid | `glyph` or `Icon name` is not an `ICON_PATHS` key (`packages/ui/src/icons/Icon.tsrx` falls back to `modules`) |
|
|
37
37
|
| Stale data after a change | each component owns a store instance (`useMemo(() => createXClientState(), [])`); check the `store.act` that should have written it. `store.commits(cb)` and `store.stats()` from `segment-state` show what was committed |
|
|
38
|
-
| Schema error on start | `
|
|
38
|
+
| Schema error on start | `runDatabaseMigrations`: `CHECKSUM_MISMATCH` means applied SQL bytes changed; `PARTIAL_MIGRATION` means only part of a pending migration exists. Never delete or bypass the database to hide either condition; restore the shipped bytes or diagnose the partial schema |
|
|
39
39
|
|
|
40
40
|
## 2b. Reproduction snippets
|
|
41
41
|
|
|
@@ -29,26 +29,26 @@ For an edit, also read the module's current `spec/module.yaml` and write the sma
|
|
|
29
29
|
|
|
30
30
|
One pass, in this order. For each row, write the default from the card into the spec and record it as a `decisions[]` entry with `decidedBy: default`. Ask only where the answer is a business fact that no default can supply.
|
|
31
31
|
|
|
32
|
-
| Decision | Default to propose
|
|
33
|
-
| ---------------------- |
|
|
34
|
-
| Actors | Owner manages, member reads
|
|
35
|
-
| Entities and fields | One primary entity; `name` required, `maxLength` 120; no field the request did not name
|
|
36
|
-
| Uniqueness | The human-facing code is `unique: tenant`; everything else `none`
|
|
37
|
-
| States and transitions | `active` and `archived`, every transition behind the manage permission
|
|
38
|
-
| Who sees what | Both permissions in the same navigation entry; the manage action hidden without the scope
|
|
39
|
-
| What is denied | Unauthenticated 401, missing permission 403, cross-tenant read returns nothing
|
|
40
|
-
| Failure behaviour | A duplicate returns a stable conflict and changes nothing; bounds return 400
|
|
41
|
-
| Cross-module reads | None. A read of another module goes through its public capability and a declared dependency
|
|
42
|
-
| Screens | One `list` screen with the entity's identifying columns
|
|
43
|
-
| Widgets | None. A count belongs on `dashboard.metrics` only when the request asks for it
|
|
44
|
-
| Settings | None. A number the business may change later is `scope: tenant` with a stated default
|
|
45
|
-
| Feature flags | Ask for one whenever a change alters behaviour a workspace already relies on, or is hard to undo: `kind: flag`, boolean, `scope: tenant`, a stated default, and the behaviour named in an invariant
|
|
46
|
-
| Agent tools | None. A tool is a later phase and `risk` may only be `read` or `workspace-write`
|
|
47
|
-
| Outside sources | None. A named public source is `research`, with the entity its findings attach to
|
|
48
|
-
| Other systems | None. A named system is one `source` adapter per record kind, run on demand
|
|
49
|
-
| Documents | None. A named document is one `templates[]` entry on the record it describes
|
|
50
|
-
| Reports |
|
|
51
|
-
| Out of scope | Every item from the card's gap list the request touched, each with its business decision
|
|
32
|
+
| Decision | Default to propose | Lands in |
|
|
33
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
|
|
34
|
+
| Actors | Owner manages, member reads | `permissions`, `invariants` |
|
|
35
|
+
| Entities and fields | One primary entity; `name` required, `maxLength` 120; no field the request did not name | `entities[]` |
|
|
36
|
+
| Uniqueness | The human-facing code is `unique: tenant`; everything else `none` | `entities[].fields[].unique` |
|
|
37
|
+
| States and transitions | `active` and `archived`, every transition behind the manage permission | `entities[].states` |
|
|
38
|
+
| Who sees what | Both permissions in the same navigation entry; the manage action hidden without the scope | `permissions`, `screens[]`, `invariants` |
|
|
39
|
+
| What is denied | Unauthenticated 401, missing permission 403, cross-tenant read returns nothing | `acceptanceScenarios` |
|
|
40
|
+
| Failure behaviour | A duplicate returns a stable conflict and changes nothing; bounds return 400 | `invariants`, `acceptanceScenarios` |
|
|
41
|
+
| Cross-module reads | None. A read of another module goes through its public capability and a declared dependency | `dependencies`, `dataOwnership` |
|
|
42
|
+
| Screens | One `list` screen with the entity's identifying columns | `screens[]` |
|
|
43
|
+
| Widgets | None. A count belongs on `dashboard.metrics` only when the request asks for it | `widgets[]` |
|
|
44
|
+
| Settings | None. A number the business may change later is `scope: tenant` with a stated default | `settings[]` |
|
|
45
|
+
| Feature flags | Ask for one whenever a change alters behaviour a workspace already relies on, or is hard to undo: `kind: flag`, boolean, `scope: tenant`, a stated default, and the behaviour named in an invariant | `settings[]` |
|
|
46
|
+
| Agent tools | None. A tool is a later phase and `risk` may only be `read` or `workspace-write` | `agentTools[]` |
|
|
47
|
+
| Outside sources | None. A named public source is `research`, with the entity its findings attach to | `research` |
|
|
48
|
+
| Other systems | None. A named system is one `source` adapter per record kind, run on demand | `adapters[]` |
|
|
49
|
+
| Documents | None. A named document is one `templates[]` entry on the record it describes | `templates[]` |
|
|
50
|
+
| Reports | A named report is one provider on `reports.v1` returning tiles and series; a named list export is one `defineListExport`; named records are findable through `search.providers.v1`. None of the three has a specification key, so each needs a decision naming the screen or the `actions[]` entry that registers it | `actions[]`, `invariants` |
|
|
51
|
+
| Out of scope | Every item from the card's gap list the request touched, each with its business decision | `outOfScope[]`, `decisions[]` |
|
|
52
52
|
|
|
53
53
|
A default you propose is still a decision: it goes into `decisions[]` so the operator can see and overturn it, and so the next agent never re-derives it.
|
|
54
54
|
|
|
@@ -86,7 +86,7 @@ Read-only master-detail (runs, playground) keeps `ui-two-col` (+ `--wide-aside`)
|
|
|
86
86
|
- `Alert`: `tone` danger (default), warning, info.
|
|
87
87
|
- `Avatar`: `name`, `square` (organizations), `large`.
|
|
88
88
|
- `Icon`: `name`, `size` (18 default, 16 in controls, 14 in `Button size="sm"`), `strokeWidth`.
|
|
89
|
-
- `BrandMark`: `size`, `
|
|
89
|
+
- `BrandMark`: `size`, `tone`; three bars with a copper accent bar, brand moments only.
|
|
90
90
|
|
|
91
91
|
Icon keys (`ICON_PATHS`, `packages/ui/src/icons/Icon.tsrx`): `dashboard`, `parties`, `catalog`, `user`, `users`, `shield`, `code`, `modules`, `file-text`, `play`, `bot`, `flask`, `activity`, `plug`, `search`, `chevron-down`, `chevron-left`, `chevron-right`, `chevrons-up-down`, `sort`, `calendar`, `plus`, `panel-left`, `check`, `filter`, `download`, `more`, `external`, `alert`, `x`, `sign-out`, `refresh`, `help`, `info`, `key`, `settings`, `braces`, `copy`. An unknown name renders `modules` silently, so check the list.
|
|
92
92
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: module-executor
|
|
3
|
+
targets: ['*']
|
|
4
|
+
description: >-
|
|
5
|
+
Implement one Flowdular blueprint end to end at the repository root: scaffold
|
|
6
|
+
from an approved spec, write the module, run the gates and join it to the
|
|
7
|
+
platform through the CLI. Use once a spec is approved and the change is ready
|
|
8
|
+
to be built.
|
|
9
|
+
claudecode:
|
|
10
|
+
model: inherit
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Your role prompt is `.ai/agents/module-executor.md`. Read it with the blueprint
|
|
14
|
+
under `.ai/blueprints/<id>/` and the one matching skill in
|
|
15
|
+
`.ai/skills/<name>/SKILL.md` before changing anything.
|
|
16
|
+
|
|
17
|
+
Implement only what the approved spec's acceptance scenarios describe, inside the
|
|
18
|
+
blueprint's `allowed-paths.yaml`. Join the platform through
|
|
19
|
+
`pnpm flowdular module enable <id> --apply` and `auth sync-scopes`; never edit
|
|
20
|
+
`flowdular.json`, `platform/package.json`, `platform/src/generated/**` or
|
|
21
|
+
`platform/octane.config.ts` by hand.
|
|
22
|
+
|
|
23
|
+
Run the module gates and `pnpm verify` yourself and report their exact commands
|
|
24
|
+
and results. Never waive a gate. End with `HANDOFF: reviewer - <what to review>`
|
|
25
|
+
or `HANDOFF: none - <blocker>`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
targets: ['*']
|
|
4
|
+
description: >-
|
|
5
|
+
Review a finished Flowdular change against its approved spec, the blueprint,
|
|
6
|
+
the invariants and the executable evidence, and report findings by severity.
|
|
7
|
+
Use as a separate phase before delivery or a pull request. Reports defects and
|
|
8
|
+
fixes nothing.
|
|
9
|
+
claudecode:
|
|
10
|
+
model: inherit
|
|
11
|
+
tools: ['Read', 'Grep', 'Glob', 'Bash']
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Your role prompt is `.ai/agents/reviewer.md` and the one task skill for this
|
|
15
|
+
phase is `.ai/skills/auto-review/SKILL.md`. Read both before reviewing.
|
|
16
|
+
|
|
17
|
+
You write no production code. Review the complete requested change, its
|
|
18
|
+
requirements, callers and tests; report concrete findings by severity with file,
|
|
19
|
+
line and failure scenario. Never waive missing or failing verification, and never
|
|
20
|
+
approve a change whose evidence you have not seen run.
|
|
21
|
+
|
|
22
|
+
End with `HANDOFF: module-executor - <findings to fix>` or
|
|
23
|
+
`HANDOFF: none - <review result and remaining verification>`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-author
|
|
3
|
+
targets: ['*']
|
|
4
|
+
description: >-
|
|
5
|
+
Turn a business request into a schema-valid Flowdular module specification at
|
|
6
|
+
the repository root. Use before any implementation, for a new module spec or a
|
|
7
|
+
change to an existing one. Writes only modules/<dir>/spec/module.yaml and never
|
|
8
|
+
approves it.
|
|
9
|
+
claudecode:
|
|
10
|
+
model: inherit
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Your role prompt is `.ai/agents/spec-author.md` and the one task skill for this
|
|
14
|
+
phase is `.ai/skills/spec-interview/SKILL.md`. Read both before writing.
|
|
15
|
+
|
|
16
|
+
You write only `modules/<dir>/spec/module.yaml`. Propose a platform default for
|
|
17
|
+
every decision and ask the user for what cannot be inferred; never guess a
|
|
18
|
+
business fact. Never set `status: approved`: approval is the user's, recorded by
|
|
19
|
+
the `spec-approval` skill.
|
|
20
|
+
|
|
21
|
+
`pnpm flowdular spec validate --all --json` must report the file valid before you
|
|
22
|
+
report. End with `HANDOFF: reviewer - spec ready for owner approval` or
|
|
23
|
+
`HANDOFF: none - <open question>`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: module-executor
|
|
3
|
+
description: >-
|
|
4
|
+
Implement one Flowdular blueprint end to end at the repository root: scaffold
|
|
5
|
+
from an approved spec, write the module, run the gates and join it to the
|
|
6
|
+
platform through the CLI. Use once a spec is approved and the change is ready
|
|
7
|
+
to be built.
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
Your role prompt is `.ai/agents/module-executor.md`. Read it with the blueprint
|
|
11
|
+
under `.ai/blueprints/<id>/` and the one matching skill in
|
|
12
|
+
`.ai/skills/<name>/SKILL.md` before changing anything.
|
|
13
|
+
|
|
14
|
+
Implement only what the approved spec's acceptance scenarios describe, inside the
|
|
15
|
+
blueprint's `allowed-paths.yaml`. Join the platform through
|
|
16
|
+
`pnpm flowdular module enable <id> --apply` and `auth sync-scopes`; never edit
|
|
17
|
+
`flowdular.json`, `platform/package.json`, `platform/src/generated/**` or
|
|
18
|
+
`platform/octane.config.ts` by hand.
|
|
19
|
+
|
|
20
|
+
Run the module gates and `pnpm verify` yourself and report their exact commands
|
|
21
|
+
and results. Never waive a gate. End with `HANDOFF: reviewer - <what to review>`
|
|
22
|
+
or `HANDOFF: none - <blocker>`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: >-
|
|
4
|
+
Review a finished Flowdular change against its approved spec, the blueprint,
|
|
5
|
+
the invariants and the executable evidence, and report findings by severity.
|
|
6
|
+
Use as a separate phase before delivery or a pull request. Reports defects and
|
|
7
|
+
fixes nothing.
|
|
8
|
+
model: inherit
|
|
9
|
+
tools:
|
|
10
|
+
- Read
|
|
11
|
+
- Grep
|
|
12
|
+
- Glob
|
|
13
|
+
- Bash
|
|
14
|
+
---
|
|
15
|
+
Your role prompt is `.ai/agents/reviewer.md` and the one task skill for this
|
|
16
|
+
phase is `.ai/skills/auto-review/SKILL.md`. Read both before reviewing.
|
|
17
|
+
|
|
18
|
+
You write no production code. Review the complete requested change, its
|
|
19
|
+
requirements, callers and tests; report concrete findings by severity with file,
|
|
20
|
+
line and failure scenario. Never waive missing or failing verification, and never
|
|
21
|
+
approve a change whose evidence you have not seen run.
|
|
22
|
+
|
|
23
|
+
End with `HANDOFF: module-executor - <findings to fix>` or
|
|
24
|
+
`HANDOFF: none - <review result and remaining verification>`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-author
|
|
3
|
+
description: >-
|
|
4
|
+
Turn a business request into a schema-valid Flowdular module specification at
|
|
5
|
+
the repository root. Use before any implementation, for a new module spec or a
|
|
6
|
+
change to an existing one. Writes only modules/<dir>/spec/module.yaml and
|
|
7
|
+
never approves it.
|
|
8
|
+
model: inherit
|
|
9
|
+
---
|
|
10
|
+
Your role prompt is `.ai/agents/spec-author.md` and the one task skill for this
|
|
11
|
+
phase is `.ai/skills/spec-interview/SKILL.md`. Read both before writing.
|
|
12
|
+
|
|
13
|
+
You write only `modules/<dir>/spec/module.yaml`. Propose a platform default for
|
|
14
|
+
every decision and ask the user for what cannot be inferred; never guess a
|
|
15
|
+
business fact. Never set `status: approved`: approval is the user's, recorded by
|
|
16
|
+
the `spec-approval` skill.
|
|
17
|
+
|
|
18
|
+
`pnpm flowdular spec validate --all --json` must report the file valid before you
|
|
19
|
+
report. End with `HANDOFF: reviewer - spec ready for owner approval` or
|
|
20
|
+
`HANDOFF: none - <open question>`.
|
|
@@ -74,7 +74,7 @@ Report each finding as: severity (`blocker`, `should-fix`, `taste`), claim, `fil
|
|
|
74
74
|
```text
|
|
75
75
|
blocker Tenant id read from body modules/inventory/src/api/endpoints.ts:41
|
|
76
76
|
A member of tenant A posts { tenantId: "B" } and creates a location in B.
|
|
77
|
-
AGENTS.md
|
|
77
|
+
AGENTS.md 4. Fix: principalFromContext(octane)!.tenantId; drop the field.
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
## 8. Known platform gaps to keep in mind (not module defects)
|
|
@@ -29,7 +29,7 @@ description: >-
|
|
|
29
29
|
| View falls back to the dashboard | `ApplicationShell.tsrx` renders `overview` for a view id that no visible navigation or account menu entry reaches |
|
|
30
30
|
| Icon renders as a grid | `glyph` or `Icon name` is not an `ICON_PATHS` key (`packages/ui/src/icons/Icon.tsrx` falls back to `modules`) |
|
|
31
31
|
| Stale data after a change | each component owns a store instance (`useMemo(() => createXClientState(), [])`); check the `store.act` that should have written it. `store.commits(cb)` and `store.stats()` from `segment-state` show what was committed |
|
|
32
|
-
| Schema error on start | `
|
|
32
|
+
| Schema error on start | `runDatabaseMigrations`: `CHECKSUM_MISMATCH` means applied SQL bytes changed; `PARTIAL_MIGRATION` means only part of a pending migration exists. Never delete or bypass the database to hide either condition; restore the shipped bytes or diagnose the partial schema |
|
|
33
33
|
|
|
34
34
|
## 2b. Reproduction snippets
|
|
35
35
|
|