@jskit-ai/agent-docs 0.1.2 → 0.1.4

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.
Files changed (45) hide show
  1. package/DISTR_AGENT.md +20 -3
  2. package/guide/agent/app-extras/assistant.md +1 -1
  3. package/guide/agent/app-extras/realtime.md +1 -1
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +1 -1
  5. package/guide/agent/app-setup/authentication.md +9 -1
  6. package/guide/agent/app-setup/console.md +1 -1
  7. package/guide/agent/app-setup/database-layer.md +1 -1
  8. package/guide/agent/app-setup/initial-scaffolding.md +22 -5
  9. package/guide/agent/app-setup/multi-homing.md +3 -1
  10. package/guide/agent/app-setup/users.md +1 -1
  11. package/guide/agent/app-setup/working-with-the-jskit-cli.md +54 -2
  12. package/guide/agent/generators/advanced-cruds.md +163 -1
  13. package/guide/agent/generators/crud-generators.md +30 -1
  14. package/guide/agent/generators/intro.md +1 -1
  15. package/guide/agent/generators/ui-generators.md +1 -1
  16. package/guide/agent/index.md +1 -1
  17. package/package.json +2 -1
  18. package/reference/autogen/packages/agent-docs.md +18 -0
  19. package/reference/autogen/tooling/jskit-cli.md +61 -0
  20. package/skills/jskit-review/SKILL.md +94 -0
  21. package/skills/jskit-review/agents/openai.yaml +4 -0
  22. package/templates/APP_BLUEPRINT.md +23 -0
  23. package/templates/WORKBOARD.md +46 -0
  24. package/templates/app/AGENTS.md +28 -3
  25. package/workflow/app-state.md +2 -1
  26. package/workflow/bootstrap.md +38 -3
  27. package/workflow/feature-delivery.md +49 -7
  28. package/workflow/review.md +33 -8
  29. package/workflow/scoping.md +24 -3
  30. package/workflow/workboard.md +29 -0
  31. package/guide/human/app-extras/assistant.md +0 -695
  32. package/guide/human/app-extras/realtime.md +0 -270
  33. package/guide/human/app-setup/a-more-interesting-shell.md +0 -734
  34. package/guide/human/app-setup/authentication.md +0 -963
  35. package/guide/human/app-setup/console.md +0 -352
  36. package/guide/human/app-setup/database-layer.md +0 -822
  37. package/guide/human/app-setup/initial-scaffolding.md +0 -738
  38. package/guide/human/app-setup/multi-homing.md +0 -795
  39. package/guide/human/app-setup/users.md +0 -404
  40. package/guide/human/app-setup/working-with-the-jskit-cli.md +0 -997
  41. package/guide/human/generators/advanced-cruds.md +0 -923
  42. package/guide/human/generators/crud-generators.md +0 -556
  43. package/guide/human/generators/intro.md +0 -109
  44. package/guide/human/generators/ui-generators.md +0 -665
  45. package/guide/human/index.md +0 -39
package/DISTR_AGENT.md CHANGED
@@ -5,21 +5,38 @@ Read these in order:
5
5
  1. `workflow/app-state.md`
6
6
  2. `workflow/bootstrap.md` if the workspace is empty or no JSKIT app exists yet
7
7
  3. `workflow/scoping.md`
8
- 4. `workflow/feature-delivery.md`
9
- 5. `workflow/review.md`
8
+ 4. `workflow/workboard.md`
9
+ 5. `workflow/feature-delivery.md`
10
+ 6. `workflow/review.md`
10
11
 
11
12
  Use these references on demand:
12
13
 
13
14
  - `reference/autogen/KERNEL_MAP.md`
14
15
  - `reference/autogen/README.md`
15
16
  - `guide/agent/index.md`
16
- - `guide/human/index.md` when compressed guidance is ambiguous or missing nuance
17
+ - `site/guide/index.md` when compressed guidance is ambiguous or missing nuance
17
18
  - `templates/APP_BLUEPRINT.md`
19
+ - `templates/WORKBOARD.md`
20
+ - `skills/jskit-review/SKILL.md` for review passes when your Codex environment supports packaged skills
18
21
 
19
22
  Core rules:
20
23
 
21
24
  - Inspect the workspace before assuming a JSKIT app exists.
25
+ - Before non-trivial edits, print a short visible checkpoint using this format:
26
+ - `Problem: ...`
27
+ - `Fix: ...`
28
+ - `Why this sticks: ...`
29
+ - `Not doing: ...`
30
+ - Keep that checkpoint compact. Do not expand it into a long preamble unless the developer asks for detail.
22
31
  - Reuse existing JSKIT helpers and runtime seams before adding new local helpers.
32
+ - A freshly scaffolded JSKIT app can still be in Stage 1. If platform decisions are not settled yet, continue with the initialize workflow before adding runtime packages.
33
+ - Do not treat a missing `config.tenancyMode` line or an untouched minimal scaffold as a final tenancy decision.
34
+ - Do not install tenancy-sensitive packages until Stage 1 decisions are complete and the chosen tenancy is written into `config/public.js`.
35
+ - Treat standard JSKIT package-owned workflows as the default baseline once the relevant package stack is chosen. Do not ask the developer to redesign those flows unless they want overrides, restrictions, or custom additions.
36
+ - Example: if the app is workspace-capable and uses `workspaces-core` plus `workspaces-web`, assume the standard workspace invite flow is part of the baseline package behavior.
37
+ - For baseline package setup, ask plainly for the exact local development values needed for the next install step, but only for the modules or packages that are actually selected.
38
+ - Use the real env var names or option names instead of vague requests for "credentials". Values such as `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `AUTH_SUPABASE_URL`, `AUTH_SUPABASE_PUBLISHABLE_KEY`, and `APP_PUBLIC_URL` are routine setup inputs when the relevant package stack needs them.
23
39
  - Do not implement app features before the blueprint has the database, surfaces, ownership model, and route/screen plan written down.
40
+ - For substantial or multi-chunk work, create or update `.jskit/WORKBOARD.md` as the per-request execution tracker.
24
41
  - Use the compressed guide first for speed; fall back to the human guide when a workflow trap, migration caveat, or architectural boundary needs exact wording.
25
42
  - Treat generated reference maps and guide copies as vendor reference. Do not edit them manually.
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-extras/assistant.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-extras/assistant.md`. Do not edit manually. -->
2
2
 
3
3
  # Assistant
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-extras/realtime.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-extras/realtime.md`. Do not edit manually. -->
2
2
 
3
3
  # Realtime
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/a-more-interesting-shell.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/a-more-interesting-shell.md`. Do not edit manually. -->
2
2
 
3
3
  # A more interesting shell
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/authentication.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/authentication.md`. Do not edit manually. -->
2
2
 
3
3
  # Authentication
4
4
 
@@ -44,6 +44,14 @@ JSKIT uses the project URL as `AUTH_SUPABASE_URL`, the publishable key as `AUTH_
44
44
 
45
45
  Use the **publishable** key here, not the secret key and not a service-role key. If you later run the app on a different host or port, update both Supabase's URL settings and `APP_PUBLIC_URL` to match the real browser URL exactly.
46
46
 
47
+ If you are guiding someone interactively, ask plainly for these exact values:
48
+
49
+ - `AUTH_SUPABASE_URL`
50
+ - `AUTH_SUPABASE_PUBLISHABLE_KEY`
51
+ - whether `APP_PUBLIC_URL` should stay `http://localhost:5173`
52
+
53
+ Do not hide behind vague language like "send the auth credentials later." In this local guide flow, those are routine setup values for the Supabase auth install step.
54
+
47
55
  ## Installing the auth layer
48
56
 
49
57
  From inside `exampleapp`, run:
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/console.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/console.md`. Do not edit manually. -->
2
2
 
3
3
  # Console
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/database-layer.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/database-layer.md`. Do not edit manually. -->
2
2
 
3
3
  # Database layer
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/initial-scaffolding.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/initial-scaffolding.md`. Do not edit manually. -->
2
2
 
3
3
  # Initial scaffolding
4
4
 
@@ -14,6 +14,16 @@ npm install
14
14
 
15
15
  The first command creates a new folder called `exampleapp` and fills it with JSKIT's base shell template. The `exampleapp` name is used in a few template replacements, such as the package name and the browser title. The `--tenancy-mode none` flag tells JSKIT to start with the smallest routing model. In this mode, the app is not workspace-aware (more of this later in the guide, when multihoming is introduced). That keeps the first scaffold easier to read because there is no workspace slug handling yet.
16
16
 
17
+ If you are working with an AI agent and want the agent to explain the platform options after the scaffold exists, there is also a safe guided path:
18
+
19
+ ```bash
20
+ npx @jskit-ai/create-app exampleapp
21
+ cd exampleapp
22
+ npm install
23
+ ```
24
+
25
+ That produces the same minimal scaffold shape, but without writing an explicit `config.tenancyMode` line yet. The important rule is that this does **not** mean tenancy is already decided. Before installing tenancy-sensitive packages such as `workspaces-core` or `workspaces-web`, the agent still needs to finish the Stage 1 platform conversation and then write the chosen tenancy into `config/public.js`. If workspace packages are installed while the app is still effectively on `none`, you fall into the recovery path described later in the multi-homing chapter.
26
+
17
27
  After creating the scaffolding (which comes with a package.json file), you will need to run `npm install` to install dependencies.
18
28
 
19
29
  **Try Bash Completion!**
@@ -103,6 +113,7 @@ The most important parts look like this:
103
113
  "server": "node ./bin/server.js",
104
114
  "server:all": "node ./bin/server.js",
105
115
  "server:home": "SERVER_SURFACE=home node ./bin/server.js",
116
+ "devlinks": "jskit app link-local-packages",
106
117
  "dev": "vite",
107
118
  "dev:all": "vite",
108
119
  "dev:home": "VITE_SURFACE=home vite",
@@ -111,7 +122,9 @@ The most important parts look like this:
111
122
  "build:home": "VITE_SURFACE=home vite build",
112
123
  "test": "node --test",
113
124
  "test:client": "vitest run tests/client",
114
- "verify": "npm run lint && npm run test && npm run test:client && npm run build && npx jskit doctor"
125
+ "verify": "jskit app verify && npm run --if-present verify:app",
126
+ "release": "jskit app release",
127
+ "jskit:update": "jskit app update-packages"
115
128
  },
116
129
  "dependencies": {
117
130
  "@local/main": "file:packages/main",
@@ -130,9 +143,13 @@ The most important parts look like this:
130
143
  }
131
144
  ```
132
145
 
133
- There are two details worth noticing immediately. The dependency on `@local/main` points at `file:packages/main`, which means your app already contains its own local JSKIT package. The `verify` script is also useful to notice early, because it shows the default quality gate the scaffold expects you to run later.
146
+ There are two details worth noticing immediately. The dependency on `@local/main` points at `file:packages/main`, which means your app already contains its own local JSKIT package. The maintenance scripts are also useful to notice early, because they show an important ownership boundary in JSKIT.
147
+
148
+ `verify`, `jskit:update`, `devlinks`, and `release` are intentionally thin wrappers. They stay in `package.json` because they are convenient app-local shortcuts, but the real implementation now lives in `jskit app ...`, not in copied scaffold scripts.
149
+
150
+ That matters because JSKIT maintenance policy changes over time. If the scaffold copied a large shell script into every app, existing apps would freeze the old behavior forever. By delegating to `jskit app verify`, `jskit app update-packages`, `jskit app link-local-packages`, and `jskit app release`, the app keeps the nice `npm run` shortcuts while the maintained behavior stays in the installed CLI package.
134
151
 
135
- The last command in that script, `npx jskit doctor`, is worth noticing specifically. Linting, tests, and builds check your source code and runtime behavior. `doctor` checks JSKIT-managed app state: installed package visibility, lock-file-backed managed files, and other JSKIT-specific health rules. It is there because a JSKIT app is not only code. It is also a descriptor-driven managed project.
152
+ `jskit app verify` is worth noticing specifically. Linting, tests, and builds check your source code and runtime behavior. The JSKIT part of that flow runs `doctor`, which checks JSKIT-managed app state: installed package visibility, lock-file-backed managed files, and other JSKIT-specific health rules. It is there because a JSKIT app is not only code. It is also a descriptor-driven managed project.
136
153
 
137
154
  The surface-specific script names are also worth noticing early, even in this tiny app. `dev:home`, `server:home`, and `build:home` are the first concrete places where surface selection shows up in the scaffold. They work by setting `VITE_SURFACE=home` on the client side and `SERVER_SURFACE=home` on the server side. In this first chapter, where `home` is the only surface, those variants behave almost the same as the default commands. Later, once more surfaces exist, those scripts become the simplest way to run or build just one surface at a time.
138
155
 
@@ -699,7 +716,7 @@ That is why you saw `@jskit-ai/kernel` and `@jskit-ai/http-runtime` earlier in `
699
716
 
700
717
  ### Other files and options
701
718
 
702
- The remaining files are easier to understand once you know the core pieces above. `vite.config.mjs` configures the frontend build and the `/api` proxy used during development. `index.html` is the HTML shell Vite uses to mount Vue. `tests/` contains basic smoke tests so the app has a verification path from day one. The `scripts/` directory collects helper scripts for release, updating JSKIT packages, and linking a local JSKIT checkout during framework development.
719
+ The remaining files are easier to understand once you know the core pieces above. `vite.config.mjs` configures the frontend build and the `/api` proxy used during development. `index.html` is the HTML shell Vite uses to mount Vue. `tests/` contains basic smoke tests so the app has a verification path from day one. The `scripts/` directory is now much smaller than it used to be, because JSKIT maintenance helpers such as `verify`, `jskit:update`, `devlinks`, and `release` are package-owned CLI commands rather than copied app scripts.
703
720
 
704
721
  The `create-app` command also accepts a few other flags that are useful without changing the basic meaning of this chapter's setup. `--title <text>` lets you replace the browser title and other template text with a friendlier app name. `--target <path>` lets you choose a different output directory instead of the default `./exampleapp`. `--tenancy-mode <mode>` can seed `none`, `personal`, or `workspaces`; for this chapter we intentionally use `none` so the first scaffold stays small and non-workspace. `--force` allows writing into a non-empty target directory when you know that is what you want. `--dry-run` prints the planned file writes without touching the filesystem, which is useful when you want to inspect what the generator would do. `-h` or `--help` prints the command help.
705
722
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/multi-homing.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/multi-homing.md`. Do not edit manually. -->
2
2
 
3
3
  # Multi-homing
4
4
 
@@ -33,6 +33,8 @@ This chapter teaches `personal`, not `workspaces`.
33
33
 
34
34
  That is deliberate. `personal` gives the guide a much better first-run experience because the first workspace is auto-provisioned for the user. The app still becomes multi-homing-capable, because invitations and memberships can still put one user in several workspaces at once. The `personal` part only changes how the first workspace is provisioned and how its slug policy works.
35
35
 
36
+ Once `workspaces-core` and `workspaces-web` are installed, the baseline workspace invitation flow is already part of the package stack. Treat that as the default behavior unless the app explicitly needs custom invite rules or custom UI beyond what the packages already provide.
37
+
36
38
  ## Installing the workspace packages
37
39
 
38
40
  If your app is already on `tenancyMode = "personal"`, run:
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/users.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/users.md`. Do not edit manually. -->
2
2
 
3
3
  # Users
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/working-with-the-jskit-cli.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/working-with-the-jskit-cli.md`. Do not edit manually. -->
2
2
 
3
3
  # Working with the JSKIT CLI
4
4
 
@@ -45,6 +45,56 @@ That lock file is the source of truth for installed JSKIT-managed package state.
45
45
 
46
46
  That is why commands such as `update`, `remove`, `position`, `migrations`, and `doctor` all care about `.jskit/lock.json`.
47
47
 
48
+ ## JSKIT-managed app maintenance scripts
49
+
50
+ The scaffolded app also has a small set of `npm run` shortcuts that are really wrappers around JSKIT-owned maintenance behavior.
51
+
52
+ The important examples are:
53
+
54
+ - `npm run verify`
55
+ - `npm run jskit:update`
56
+ - `npm run devlinks`
57
+ - `npm run release`
58
+
59
+ In the current scaffold, those scripts are intentionally thin:
60
+
61
+ ```json
62
+ {
63
+ "scripts": {
64
+ "verify": "jskit app verify && npm run --if-present verify:app",
65
+ "jskit:update": "jskit app update-packages",
66
+ "devlinks": "jskit app link-local-packages",
67
+ "release": "jskit app release"
68
+ }
69
+ }
70
+ ```
71
+
72
+ That is a deliberate design choice.
73
+
74
+ The app keeps the handy `npm run` names, but the real maintenance policy now lives in the installed CLI package instead of copied shell scripts inside the app. That means if JSKIT later changes how package updates, local linking, or baseline verification should work, apps can pick up the new behavior by updating `@jskit-ai/jskit-cli` instead of hand-editing frozen scaffold files.
75
+
76
+ This gives you a clean ownership split:
77
+
78
+ - app-owned scripts still describe how *this app* runs, builds, and tests
79
+ - JSKIT-owned wrapper scripts delegate framework maintenance to `jskit app ...`
80
+
81
+ That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, that is now shorthand for "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
82
+
83
+ If your app uses a non-default npm registry for JSKIT packages, pass it to the maintained CLI command rather than hard-coding it in the scaffold. For example:
84
+
85
+ ```bash
86
+ npm run jskit:update -- --registry https://registry.example.com
87
+ npm run release -- --registry https://registry.example.com
88
+ ```
89
+
90
+ For older apps that still carry copied maintenance scripts, the migration path is:
91
+
92
+ ```bash
93
+ npx jskit app adopt-managed-scripts
94
+ ```
95
+
96
+ That command rewrites known old scaffold values to the thin wrapper form above.
97
+
48
98
  ## Discover first, change second
49
99
 
50
100
  One of the best habits in JSKIT is to inspect the catalog before mutating the app.
@@ -59,6 +109,7 @@ npx jskit help
59
109
 
60
110
  That shows the available commands such as:
61
111
 
112
+ - `app`
62
113
  - `list`
63
114
  - `show`
64
115
  - `add`
@@ -72,6 +123,7 @@ That shows the available commands such as:
72
123
  Every command in the CLI also has its own help page. For example:
73
124
 
74
125
  ```bash
126
+ npx jskit help app
75
127
  npx jskit help add
76
128
  npx jskit help migrations
77
129
  ```
@@ -642,7 +694,7 @@ That is a different job from:
642
694
 
643
695
  Those commands can all pass while JSKIT-managed state is still inconsistent. `doctor` is the command that checks that JSKIT's own view of the app still makes sense.
644
696
 
645
- That is exactly why the starter scaffold already includes `npx jskit doctor` in `npm run verify`.
697
+ That is exactly why the starter scaffold now routes `npm run verify` through `jskit app verify`.
646
698
 
647
699
  It belongs there because JSKIT apps are not only source trees. They also have:
648
700
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/advanced-cruds.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/advanced-cruds.md`. Do not edit manually. -->
2
2
 
3
3
  # Advanced CRUDs
4
4
 
@@ -451,6 +451,168 @@ They usually:
451
451
 
452
452
  These files are mostly containers. That is deliberate.
453
453
 
454
+ ### CRUD link resolution
455
+
456
+ This deserves an explicit warning, because it was implemented incorrectly in a real app.
457
+
458
+ When you customize generated CRUD pages, use the CRUD runtime that owns the current route scope to resolve CRUD-bound links.
459
+
460
+ Use `paths.page()` for **surface-aware** navigation:
461
+
462
+ - `/account`
463
+ - `/assistant`
464
+ - `/lists`
465
+ - other links that only need normal surface params such as `workspaceSlug`
466
+
467
+ Do **not** use `paths.page()` with CRUD record placeholders inside the relative path or URL template, such as:
468
+
469
+ - `:contactId`
470
+ - `:addressId`
471
+ - `:todoListId`
472
+ - `:todoItemId`
473
+
474
+ For CRUD-bound links, use the runtime-provided resolvers instead:
475
+
476
+ - list pages:
477
+ - `records.resolveViewUrl(record)`
478
+ - `records.resolveEditUrl(record)`
479
+ - `records.resolveParams(template, extraParams)`
480
+ - view pages:
481
+ - `view.listUrl`
482
+ - `view.editUrl`
483
+ - `view.resolveParams(template, extraParams)`
484
+ - add/edit pages:
485
+ - `formRuntime.addEdit.resolveParams(template, extraParams)`
486
+
487
+ Why this matters:
488
+
489
+ - `paths.page()` only knows about the current surface route params
490
+ - CRUD runtimes also know about the current CRUD route shape, current record id, parent record ids, and nested child route context
491
+ - once a page is CRUD-bound, those runtime resolvers are the safe way to build record-scoped links
492
+
493
+ Scope rule:
494
+
495
+ - use the runtime anchored to the record that owns the action
496
+ - on a parent record view page with nested child routes, parent actions should still resolve from the parent `view` runtime even while a child route like `/items/new` is active
497
+ - child-item actions should resolve from the child/item runtime only when the current route is actually child-scoped
498
+
499
+ Examples:
500
+
501
+ - good: `view.resolveParams("./items/new")`
502
+ - good: `view.resolveParams("./items/:todoItemId/edit", { todoItemId: item.id })`
503
+ - good: `formRuntime.addEdit.resolveParams("../../..")`
504
+ - bad: `paths.page("/lists/:todoListId/items/new")`
505
+ - bad: `paths.page("/lists/:todoListId/edit")`
506
+
507
+ The safe mental model is:
508
+
509
+ - use `paths.page()` to get to the right surface
510
+ - use CRUD runtime resolvers to move around inside the CRUD
511
+
512
+ ### Live actions and `useCommand()`
513
+
514
+ There is one more client-side pattern worth naming explicitly:
515
+
516
+ Use `useCommand()` for live actions such as:
517
+
518
+ - checkboxes that toggle a record field
519
+ - archive / publish / reopen buttons
520
+ - delete buttons
521
+ - small one-click PATCH / POST / DELETE actions that are not full forms
522
+
523
+ This is the pattern the `todo` app uses for "mark item done".
524
+
525
+ The page renders a checkbox like this:
526
+
527
+ ```vue
528
+ <v-checkbox-btn
529
+ :model-value="item.done"
530
+ :disabled="!canUpdateItem || isItemBusy(item.id)"
531
+ @update:model-value="toggleItem(item, $event)"
532
+ />
533
+ ```
534
+
535
+ Then the page wires a command:
536
+
537
+ ```js
538
+ const itemPatchModel = reactive({
539
+ id: "",
540
+ patch: {}
541
+ });
542
+
543
+ const updateItemCommand = useCommand({
544
+ model: itemPatchModel,
545
+ apiSuffix: ({ model }) => `/todo-items/${model?.id || ""}`,
546
+ writeMethod: "PATCH",
547
+ runPermissions: ["crud.todo_items.update"],
548
+ suppressSuccessMessage: true,
549
+ fallbackRunError: "Unable to update item.",
550
+ buildRawPayload(model) {
551
+ return model.patch;
552
+ },
553
+ async onRunSuccess(_payload, context = {}) {
554
+ if (context.queryClient) {
555
+ await context.queryClient.invalidateQueries({
556
+ queryKey: ["ui-generator", "todo_items"]
557
+ });
558
+ }
559
+ }
560
+ });
561
+
562
+ async function toggleItem(item = {}, nextValue = false) {
563
+ itemPatchModel.id = String(item.id || "");
564
+ itemPatchModel.patch = {
565
+ done: Boolean(nextValue)
566
+ };
567
+
568
+ await updateItemCommand.run();
569
+ }
570
+ ```
571
+
572
+ That gives you a clean action pipeline:
573
+
574
+ 1. the UI captures the click
575
+ 2. the page writes a tiny action model
576
+ 3. `useCommand()` resolves the correct scoped API path for the current route/surface
577
+ 4. it sends the request through the standard HTTP runtime
578
+ 5. on success, it invalidates the relevant query keys so the list/view refreshes
579
+
580
+ So yes: for this class of interaction, `useCommand()` is the right helper.
581
+
582
+ Use this rule of thumb:
583
+
584
+ - `useCommand()`
585
+ - for live actions
586
+ - button clicks
587
+ - toggles
588
+ - small PATCH/POST/DELETE interactions
589
+ - `useAddEdit()` / `useCrudAddEdit()`
590
+ - for real forms
591
+ - create/edit screens
592
+ - save/cancel flows
593
+ - `useCrudList()` / `useCrudView()`
594
+ - for routed list/view loading and CRUD URL resolution
595
+
596
+ Best practices for live CRUD actions:
597
+
598
+ - keep the payload narrow
599
+ - send the field change you mean, not a whole copied record
600
+ - disable the control while the command for that record is running
601
+ - `todo` does this with `isItemBusy(item.id)`
602
+ - invalidate the relevant list/view query keys on success
603
+ - do not hand-maintain parallel local record copies unless you really need optimistic UI
604
+ - suppress success toasts for high-frequency actions when they would become noisy
605
+ - a checkbox toggle usually does not need "Saved." every time
606
+ - keep business rules on the server
607
+ - in `todo`, the client sends `{ done: true|false }`
608
+ - the server service decides how `completedAt` should be set or cleared
609
+
610
+ The safe mental model is:
611
+
612
+ - use form runtimes for forms
613
+ - use command runtimes for actions
614
+ - keep the server as the source of truth for derived state
615
+
454
616
  ### `_components/CrudAddEditForm.vue`
455
617
 
456
618
  This is the shared rendering shell for the add/edit form.
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/crud-generators.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/crud-generators.md`. Do not edit manually. -->
2
2
 
3
3
  # CRUD Generators
4
4
 
@@ -238,6 +238,7 @@ The exact fields will vary by app. What matters for the generator is:
238
238
  - the table already exists
239
239
  - the ownership columns match the ownership filter you are going to choose
240
240
  - the column names are stable enough to become part of your app's resource contract
241
+ - if you are using `crud-server-generator`, do **not** hand-write a separate CRUD migration for this table; the server generator installs the CRUD migration scaffold itself
241
242
 
242
243
  In this table, `workspace_id` is the important ownership clue. That is why the next step uses:
243
244
 
@@ -261,6 +262,13 @@ npx jskit generate crud-server-generator scaffold \
261
262
 
262
263
  This creates an app-local package under `packages/contacts/`.
263
264
 
265
+ Before generating anything, decide these with the developer:
266
+
267
+ - which operations are allowed for this CRUD
268
+ - which fields belong in the list view if a list exists
269
+ - what the view form should look like
270
+ - what the edit/new form should look like
271
+
264
272
  The most important file from the UI point of view is:
265
273
 
266
274
  ```text
@@ -505,6 +513,27 @@ The host page then renders the comment list directly, usually with lower-level C
505
513
  - `useCrudAddEdit()`
506
514
  - `useCrudView()` when needed
507
515
 
516
+ There is one more runtime worth knowing about early:
517
+
518
+ - `useCommand()`
519
+
520
+ Use it for live actions that are **not** full forms, such as:
521
+
522
+ - checkbox toggles
523
+ - archive / reopen buttons
524
+ - quick PATCH / POST / DELETE actions on one record
525
+
526
+ So the practical split is:
527
+
528
+ - `useCrudList()` / `useCrudView()`
529
+ - routed list/view loading
530
+ - `useCrudAddEdit()`
531
+ - real create/edit forms
532
+ - `useCommand()`
533
+ - live actions inside the page
534
+
535
+ The `todo` app uses that last pattern for "mark item done" checkboxes. The deeper best-practices explanation is in [Advanced CRUDs](/guide/generators/advanced-cruds).
536
+
508
537
  That is the same general pattern already used in the real app for embedded child records like pet notes: the record list lives inside the main view page, while routed child pages handle the operations that still deserve their own URLs.
509
538
 
510
539
  This pattern is useful when the child records are supporting detail rather than a destination in their own right.
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/intro.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/intro.md`. Do not edit manually. -->
2
2
 
3
3
  # Generators
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/ui-generators.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/ui-generators.md`. Do not edit manually. -->
2
2
 
3
3
  # UI Generators
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by `npm run agent-docs:build` from `docs/guide/index.md`. Do not edit manually. -->
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/index.md`. Do not edit manually. -->
2
2
 
3
3
  # Guide
4
4
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Distributed JSKIT agent workflows, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "DISTR_AGENT.md",
8
8
  "guide",
9
9
  "reference",
10
+ "skills",
10
11
  "templates",
11
12
  "workflow"
12
13
  ],
@@ -11,3 +11,21 @@ Use this on demand; do not load the full index at startup.
11
11
  - Excludes: `test/`, `tests/`, `__tests__/`, `*.test.*`, `*.spec.*`, `*.vitest.*`, `node_modules/`, `dist/`, `coverage/`, `docs/`, `LEGACY/`
12
12
 
13
13
  ## Sections
14
+
15
+ ### site
16
+
17
+ ### `site/.vitepress/config.mjs`
18
+ Exports
19
+ - None
20
+
21
+ ### `site/.vitepress/theme/components/DocsInDepth.vue`
22
+ Exports
23
+ - None
24
+
25
+ ### `site/.vitepress/theme/components/DocsTerminalTip.vue`
26
+ Exports
27
+ - None
28
+
29
+ ### `site/.vitepress/theme/index.js`
30
+ Exports
31
+ - `default`
@@ -41,6 +41,8 @@ Exports
41
41
  - `upsertEnvValue(content, key, value)`
42
42
  - `removeEnvValue(content, key, expectedValue, previous)`
43
43
  - `writeJsonFile`
44
+ Local functions
45
+ - `directoryLooksLikeJskitAppRoot(directoryPath)`
44
46
 
45
47
  ### `src/server/cliRuntime/capabilitySupport.js`
46
48
  Exports
@@ -341,6 +343,65 @@ Exports
341
343
  - `applyViteMutations(packageEntry, appRoot, viteMutations, options, managedVite, touchedFiles)`
342
344
  - `removeManagedViteProxyEntries({ appRoot, packageId, managedViteChanges = {}, touchedFiles = null } = {})`
343
345
 
346
+ ### `src/server/commandHandlers/app.js`
347
+ Exports
348
+ - `createAppCommands(ctx = {})`
349
+ Local functions
350
+ - `renderAppHelp(stream, definition = null)`
351
+
352
+ ### `src/server/commandHandlers/appCommandCatalog.js`
353
+ Exports
354
+ - `APP_SCRIPT_WRAPPERS`
355
+ - `LEGACY_APP_SCRIPT_VALUES`
356
+ - `LEGACY_APP_SCRIPT_FILES`
357
+ - `APP_COMMAND_DEFINITIONS`
358
+ - `listAppCommandDefinitions()`
359
+ - `resolveAppCommandDefinition(rawName = "")`
360
+ - `buildAppCommandOptionMeta(subcommandName = "")`
361
+
362
+ ### `src/server/commandHandlers/appCommands/adoptManagedScripts.js`
363
+ Exports
364
+ - `runAppAdoptManagedScriptsCommand(ctx = {}, { appRoot = "", options = {}, stdout })`
365
+ Local functions
366
+ - `shouldRewriteScript(currentValue = "", scriptName = "", force = false)`
367
+
368
+ ### `src/server/commandHandlers/appCommands/linkLocalPackages.js`
369
+ Exports
370
+ - `runAppLinkLocalPackagesCommand(ctx = {}, { appRoot = "", options = {}, stdout })`
371
+
372
+ ### `src/server/commandHandlers/appCommands/release.js`
373
+ Exports
374
+ - `runAppReleaseCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
375
+
376
+ ### `src/server/commandHandlers/appCommands/shared.js`
377
+ Exports
378
+ - `fileExists(filePath = "")`
379
+ - `normalizeText(value = "")`
380
+ - `isTruthyFlag(rawValue = "")`
381
+ - `runExternalCommand(command, args = [], { cwd = "", env = {}, stdout, stderr, quiet = false, createCliError } = {})`
382
+ - `formatUtcReleaseTimestamp(date = new Date())`
383
+ - `resolveLocalJskitBin(appRoot = "")`
384
+ - `runLocalJskit(appRoot, args = [], { stdout, stderr, createCliError, quiet = false } = {})`
385
+ - `resolveLocalRepoRoot({ appRoot = "", explicitRepoRoot = "" } = {})`
386
+ - `discoverLocalPackageMap(repoRoot = "")`
387
+ - `linkPackageBinEntries({ appRoot, packageDirName, sourceDir, stdout } = {})`
388
+ - `resolveSymlinkType()`
389
+ Local functions
390
+ - `ensureCommandSucceeded(result, label, { createCliError, cwd = "", stdout, stderr, quiet = false } = {})`
391
+
392
+ ### `src/server/commandHandlers/appCommands/updatePackages.js`
393
+ Exports
394
+ - `runAppUpdatePackagesCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
395
+ Local functions
396
+ - `collectJskitPackageNames(packageMap = {})`
397
+ - `resolveMajorRangeFromVersion(packageName = "", rawVersion = "", createCliError)`
398
+ - `resolveRegistryArgs(registryUrl = "")`
399
+ - `resolveInstallSpecs(packageNames = [], resolveMajorRange)`
400
+
401
+ ### `src/server/commandHandlers/appCommands/verify.js`
402
+ Exports
403
+ - `runAppVerifyCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
404
+
344
405
  ### `src/server/commandHandlers/completion.js`
345
406
  Exports
346
407
  - `createCompletionCommands(ctx = {})`