@notis_ai/cli 0.2.7 → 0.2.8
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 +15 -0
- package/dist/scaffolds/notis-database/app/page.tsx +38 -41
- package/dist/scaffolds/notis-database/lib/types.ts +5 -7
- package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-fixtures.json +1839 -0
- package/dist/scaffolds/notis-database/notis.config.ts +48 -1
- package/dist/scaffolds/notis-database/package-lock.json +3935 -0
- package/dist/scaffolds/notis-database/package.json +2 -1
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/package.json +4 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectActionBar.tsx +7 -2
- package/dist/scaffolds/notis-database/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useMultiSelect.ts +38 -2
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/index.ts +30 -1
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/runtime.ts +76 -17
- package/dist/scaffolds/notis-database/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-database/src/mock-runtime.ts +4 -1
- package/dist/scaffolds/notis-journal/CHANGELOG.md +4 -0
- package/dist/scaffolds/notis-journal/app/page.tsx +1 -0
- package/dist/scaffolds/notis-journal/package-lock.json +4615 -0
- package/dist/scaffolds/notis-journal/package.json +2 -2
- package/dist/scaffolds/notis-journal/packages/sdk/src/config.ts +52 -1
- package/dist/scaffolds/notis-notes/app/page.tsx +39 -46
- package/dist/scaffolds/notis-notes/app/phosphor-icons.ts +596 -0
- package/dist/scaffolds/notis-notes/lib/visible-properties.ts +144 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-fixtures.json +752 -0
- package/dist/scaffolds/notis-notes/notis.config.ts +48 -3
- package/dist/scaffolds/notis-notes/package-lock.json +4636 -0
- package/dist/scaffolds/notis-notes/package.json +7 -3
- package/dist/scaffolds/notis-notes/packages/sdk/package.json +36 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectActionBar.tsx +278 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectCheckbox.tsx +91 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useBackend.ts +41 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useMultiSelect.ts +539 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotis.ts +34 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotisNavigation.ts +49 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTool.ts +64 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTools.ts +56 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTopBarSearch.ts +73 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/index.ts +83 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/provider.tsx +43 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/runtime.ts +220 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/ui.ts +15 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/vite.ts +56 -0
- package/dist/scaffolds/notis-notes/packages/sdk/tsconfig.json +15 -0
- package/dist/scaffolds/notis-random/CHANGELOG.md +12 -2
- package/dist/scaffolds/notis-random/app/history/page.tsx +5 -4
- package/dist/scaffolds/notis-random/app/page.tsx +141 -74
- package/dist/scaffolds/notis-random/components/ui/button.tsx +50 -0
- package/dist/scaffolds/notis-random/components/ui/card.tsx +16 -0
- package/dist/scaffolds/notis-random/components/ui/input.tsx +23 -0
- package/dist/scaffolds/notis-random/lib/notis-tools.ts +26 -7
- package/dist/scaffolds/notis-random/lib/rng.ts +179 -19
- package/dist/scaffolds/notis-random/lib/roll-record.ts +103 -16
- package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-fixtures.json +753 -0
- package/dist/scaffolds/notis-random/notis.config.ts +47 -3
- package/dist/scaffolds/notis-random/package-lock.json +4513 -0
- package/dist/scaffolds/notis-random/package.json +6 -2
- package/dist/scaffolds/notis-random/packages/sdk/package.json +36 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectActionBar.tsx +278 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectCheckbox.tsx +91 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useBackend.ts +41 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useMultiSelect.ts +539 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotis.ts +34 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotisNavigation.ts +49 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTool.ts +64 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTools.ts +56 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTopBarSearch.ts +73 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/index.ts +83 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/provider.tsx +43 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/runtime.ts +220 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/ui.ts +15 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/vite.ts +56 -0
- package/dist/scaffolds/notis-random/packages/sdk/tsconfig.json +15 -0
- package/dist/scaffolds/notis-random/tailwind.config.ts +8 -1
- package/dist/scaffolds.json +8 -17
- package/package.json +2 -1
- package/skills/notis-apps/SKILL.md +449 -144
- package/skills/notis-apps/cli.md +15 -0
- package/skills/notis-cli/SKILL.md +8 -4
- package/skills/notis-onboarding/BRIEF.md +93 -0
- package/src/cli.js +50 -12
- package/src/command-specs/apps.js +154 -21
- package/src/command-specs/index.js +2 -0
- package/src/command-specs/onboarding.js +216 -0
- package/src/command-specs/tools.js +8 -4
- package/src/runtime/app-platform.js +65 -4
- package/src/runtime/desktop-auth.js +66 -17
- package/src/runtime/errors.js +1 -0
- package/src/runtime/output.js +9 -2
- package/src/runtime/profiles.js +179 -17
- package/src/runtime/telemetry.js +92 -0
- package/src/runtime/transport.js +26 -1
- package/template/.harness/index.html.tmpl +30 -2
- package/template/packages/sdk/src/config.ts +38 -1
- package/dist/scaffolds/notis-affiliate-prospects/CHANGELOG.md +0 -7
- package/dist/scaffolds/notis-affiliate-prospects/README.md +0 -20
- package/dist/scaffolds/notis-affiliate-prospects/app/globals.css +0 -42
- package/dist/scaffolds/notis-affiliate-prospects/app/layout.tsx +0 -7
- package/dist/scaffolds/notis-affiliate-prospects/app/page.tsx +0 -248
- package/dist/scaffolds/notis-affiliate-prospects/app/prospects/page.tsx +0 -134
- package/dist/scaffolds/notis-affiliate-prospects/app/segments/page.tsx +0 -108
- package/dist/scaffolds/notis-affiliate-prospects/components/ui/card.tsx +0 -35
- package/dist/scaffolds/notis-affiliate-prospects/index.html +0 -12
- package/dist/scaffolds/notis-affiliate-prospects/lib/affiliate-data.ts +0 -218
- package/dist/scaffolds/notis-affiliate-prospects/lib/demo-prospects.ts +0 -52
- package/dist/scaffolds/notis-affiliate-prospects/lib/notis-tools.ts +0 -100
- package/dist/scaffolds/notis-affiliate-prospects/lib/utils.ts +0 -25
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-fixtures.json +0 -187
- package/dist/scaffolds/notis-affiliate-prospects/notis.config.ts +0 -65
- package/dist/scaffolds/notis-affiliate-prospects/package.json +0 -32
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/config.ts +0 -90
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/hooks/useDatabase.ts +0 -76
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/hooks/useUpsertDocument.ts +0 -50
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/styles.css +0 -38
- package/dist/scaffolds/notis-affiliate-prospects/postcss.config.mjs +0 -6
- package/dist/scaffolds/notis-affiliate-prospects/src/dev-main.tsx +0 -72
- package/dist/scaffolds/notis-affiliate-prospects/src/mock-runtime.ts +0 -242
- package/dist/scaffolds/notis-affiliate-prospects/tailwind.config.ts +0 -51
- package/dist/scaffolds/notis-affiliate-prospects/tsconfig.json +0 -23
- package/dist/scaffolds/notis-affiliate-prospects/vite.config.ts +0 -11
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useBackend.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useNotis.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useNotisNavigation.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTool.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTools.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTopBarSearch.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/provider.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/ui.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/vite.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/tsconfig.json +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-random}/components.json +0 -0
|
@@ -5,216 +5,521 @@ description: Design and package Notis apps. Use when users want an app that grou
|
|
|
5
5
|
|
|
6
6
|
# Notis Apps Skill
|
|
7
7
|
|
|
8
|
-
Use this skill when the user wants
|
|
8
|
+
Use this skill when the user wants a packaged Notis app -- task manager, CRM, dashboard, internal tool, etc. Notis apps are **Vite + React projects** that deploy into the Notis portal as installed apps for the current user or team.
|
|
9
9
|
|
|
10
10
|
Run the Notis CLI through NPX, for example `npx --package @notis_ai/cli@latest -- notis apps list`. Notis Desktop keeps the CLI auth profile current. This `notis-apps` skill is delivered through normal Notis skill sync for the signed-in user, alongside other curated skills.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
For the platform model, architecture, and local development workflow, read [docs/notis-apps-platform.md](../../../docs/notis-apps-platform.md) first. This skill is the execution guide for using that platform correctly.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## How Apps Are Built
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
- packaged as an ES module bundle
|
|
20
|
-
-
|
|
21
|
-
- connected to Notis data and tools through the Portal-provided runtime and SDK hooks
|
|
16
|
+
All Notis apps are built using the Notis CLI, either locally in a repo workspace or inside a Vercel Sandbox. The platform contract is the same in both cases:
|
|
17
|
+
- the app is a Vite + React project
|
|
18
|
+
- the app uses `@notis/sdk`
|
|
19
|
+
- the app is packaged as an ES module bundle
|
|
20
|
+
- the portal renders it as a React component inside the portal's React tree
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
## App Workspace Tool Rules
|
|
23
|
+
|
|
24
|
+
- Apps are the top-level packaging unit in Notis.
|
|
25
|
+
- Use `LOCAL_NOTIS_CREATE_APP` to register a new app, then use the Notis CLI in the shell to build and deploy it.
|
|
26
|
+
- Use `LOCAL_NOTIS_UPDATE_APP` to update app metadata.
|
|
27
|
+
- Use `LOCAL_NOTIS_LIST_APPS` to discover the user's apps.
|
|
28
|
+
- The full app lifecycle uses the CLI in the shell. Always run it through the registry-resolved package, for example `npx --package @notis_ai/cli@latest -- notis apps init`; use the same prefix for `build` and `deploy`. In hosted shells, the CLI is pre-authenticated through `NOTIS_JWT`.
|
|
29
|
+
- There are no `save_app` or `load_app` tools. Do not attempt to call them. Use only the CLI for app file operations.
|
|
30
|
+
- Use `npx --package @notis_ai/cli@latest -- notis apps scaffolds list` to discover bundled starting points before scaffolding.
|
|
31
|
+
- Use `LOCAL_NOTIS_LIST_PUBLIC_APP_STORE` only to help users choose apps to install, not as a source-clone workflow.
|
|
32
|
+
- Use `LOCAL_NOTIS_INSTALL_APP` only when the user explicitly wants to install from a listing.
|
|
33
|
+
- Before installing, inspect the listing's `required_capabilities`. Explain each
|
|
34
|
+
requested capability and obtain explicit approval; only then pass the matching
|
|
35
|
+
token in `approved_capabilities`. Never infer capability approval. The current
|
|
36
|
+
workspace-wide read token is `workspace_databases_read`.
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Notis CLI (local workspace or Vercel Sandbox)
|
|
42
|
+
-> Vite + React project with @notis/sdk
|
|
43
|
+
-> notis apps init / dev / build / verify / create / link / pull / deploy
|
|
44
|
+
-> ES module bundle (app.js + app.css) + manifest
|
|
45
|
+
-> Portal renders as React component with real tools/databases
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`deploy` updates the linked installed app for the current account or team. After the user explicitly confirms the App Details page is ready, `apps publish --confirm-ready` submits that deployed version to the Team or Public Store review flow.
|
|
49
|
+
|
|
50
|
+
### Key Components
|
|
51
|
+
|
|
52
|
+
1. **@notis/sdk** (`packages/sdk/`) -- SDK for app developers
|
|
53
|
+
- `@notis/sdk` -- NotisProvider and generic runtime hooks such as useTool and useTools
|
|
54
|
+
- `@notis/sdk/config` -- `defineNotisApp()` for notis.config.ts
|
|
55
|
+
- `@notis/sdk/vite` -- `notisViteConfig()` for vite.config.ts
|
|
56
|
+
- `@notis/sdk/styles.css` -- shadow-safe app shell styles and base app-surface classes
|
|
57
|
+
|
|
58
|
+
2. **CLI** (`packages/cli/src/command-specs/apps.js`) -- local development should center on `apps dev`, plus init, build, verify, create, deploy, link, pull, doctor, and list
|
|
59
|
+
|
|
60
|
+
3. **Server** (`server/routers/portal_views/`) -- Returns signed bundle URLs, proxies tool calls
|
|
61
|
+
|
|
62
|
+
4. **Portal** (`portal/src/components/apps/`) -- Renders app bundles as React components via AppViewRenderer
|
|
63
|
+
|
|
64
|
+
### Runtime Bridge
|
|
65
|
+
|
|
66
|
+
Apps communicate with the platform through the `NotisRuntime` interface, provided by the portal via React context:
|
|
67
|
+
|
|
68
|
+
- **Portal development**: the portal loads a local bundle for an active dev session and still provides a real `NotisRuntime`.
|
|
69
|
+
- **Portal**: the portal creates a real `NotisRuntime` and passes it as a prop to `NotisProvider`. All calls go to `/portal_views/runtime_query` via fetch with the user's JWT.
|
|
70
|
+
- The portal mounts the app inside a shadow-scoped content surface and injects the runtime before app mount. There is no supported window-global runtime fallback.
|
|
71
|
+
|
|
72
|
+
App code never accesses the runtime directly -- it uses SDK hooks (`useTool`, `useTools`, `useNotis`, etc.) which read from the `NotisProvider` context.
|
|
73
|
+
|
|
74
|
+
## Hard Rules
|
|
75
|
+
|
|
76
|
+
1. **React + Vite only** -- No Next.js, no custom server
|
|
77
|
+
2. **ES module bundle** -- Vite builds a library-mode bundle with React externalized
|
|
78
|
+
3. **Component rendering** -- Apps render as React components directly in the portal. No iframes.
|
|
79
|
+
The portal owns the `ShadowRoot`, theme tokens, and runtime provider.
|
|
80
|
+
4. **HTTP bridge** -- Runtime calls use fetch to `/portal_views/runtime_query`
|
|
81
|
+
5. **Declarative tools** -- Tool access declared in `notis.config.ts`, enforced server-side
|
|
82
|
+
6. **shadcn + Notis theme** -- Apps must use shadcn components with the live Notis theme provided by the portal
|
|
83
|
+
7. **Phosphor icons only** -- Always `phosphor:` prefix. Never emojis.
|
|
84
|
+
8. **Database refs only** -- `notis.config.ts` references existing databases by slug. The schema source of truth lives in the `databases` table, not in the manifest. Every native database is owned by exactly one app (`databases.owner_app_id`): creating one through `LOCAL_NOTIS_DATABASE_UPSERT_DATABASE` requires the owning app's slug or id in the `app` argument, install/dev materialization stamps ownership automatically, and deleting an app deletes its databases and their documents.
|
|
85
|
+
An app-owned database slug is a stable deployed contract because bundles and
|
|
86
|
+
collection routes may call it directly. Do not try to rename that slug with
|
|
87
|
+
a schema tool; rename the display title instead.
|
|
88
|
+
9. **Use NPX for CLI commands** -- Always run `npx --package @notis_ai/cli@latest -- notis ...`.
|
|
89
|
+
10. **`apps deploy` is not store publishing** -- `apps deploy` updates an installed app only and persists its source snapshot. Store review starts separately with `apps publish --confirm-ready` after explicit user approval.
|
|
90
|
+
11. **Routes are canonical** -- Define navigation only in `manifest.routes`. Every configured route must declare an explicit `slug`. Do not rely on legacy `manifest.views`.
|
|
91
|
+
12. **Portal-owned sidebars stay portal-owned** -- If a route uses `collection.sidebar`, treat that sidebar as platform chrome. Do not remove it, recreate it inside app JSX, or replace it with a custom in-app folder rail.
|
|
92
|
+
13. **Portal globals are off-limits** -- Never use `window.__NOTIS_RUNTIME__`, query portal-owned DOM hooks, or create global DOM portals.
|
|
93
|
+
14. **Prefer inline optimistic edits** -- Rename-like edits for collections, app-owned rows, and sidebar-backed entities should use inline editing with an optimistic UI update, then roll back on backend failure. Use modals only when the edit requires multiple fields or destructive confirmation.
|
|
94
|
+
15. **Local development first; deploy is user-gated** -- Iterate with `apps dev` and let the **user** test the app in the desktop **Local development** sidebar group. Do NOT run `apps create` or `apps deploy` on your own initiative, even after a clean build and verify. `deploy` installs the app onto the user's account and is a one-directional, outward-facing action — treat it like publishing: only run it when the user has tested the local build and **explicitly asks you to deploy**. Building a new app end-to-end without deploying is the expected, complete outcome. (See the **Local-development-first handoff** in the Workflow.)
|
|
95
|
+
16. **Installed app links are explicit** -- A mounted dev session updates an installed workspace app only when the local checkout is linked by app id in `.notis/state.json` and the dev-session registry mirrors that id. Name or slug matches may be suggestions, never update targets. After first install, keep that link so Portal and CLI show/update the same app instead of creating duplicates.
|
|
96
|
+
17. **Development identities stay separate** -- `.notis/state.json` uses `dev_app_id` for the hidden development-runtime row and `app_id` only for an accessible installed workspace app. The Electron registry mirrors the installed id as `targetAppId`. Never pass a runtime app whose manifest has `is_dev: true` to `notis apps link`; it is not an install/update target. Current CLIs reject that link and repair stale hidden, deleted, or inaccessible targets on the next `apps dev` without erasing valid state on transport or authentication failures.
|
|
97
|
+
18. **Mounted means Portal-acknowledged** -- A running process, registry row, or HTTP 200 proves only that the app is serving. Before telling the user an app is mounted, require the current `apps dev` process to report `Mounted in Notis`. That status comes from an exact session/app/slug/nonce acknowledgment written by Electron only after the app enters the Portal's final **Local development** sidebar model. Do not require a manual Electron route/render check merely to prove the mount; route rendering is a separate behavior or visual verification task.
|
|
98
|
+
19. **Store submission is user-gated** -- Run `apps publish --confirm-ready` only after the user explicitly confirms the current App Details page and Store listing are ready. Deploy the exact approved local state first. The command must reject missing confirmation, incomplete listing media, a local/deployed version mismatch, private visibility, or an existing pending review.
|
|
99
|
+
20. **Bump `notisAppVersion` for every Store update** -- `package.json` must contain a semver `notisAppVersion`. For an existing Store app, increment it beyond the currently published registry version before deploy and submission; registry CI rejects equal or lower versions.
|
|
100
|
+
21. **`CHANGELOG.md` owns release history** -- Keep the complete release history in one root `CHANGELOG.md`, newest entry first. Do not add new `versionNotes` values to `notis.config.ts`. Use `## [Release title] - YYYY-MM-DD`, or `{PR_MERGE_DATE}` for an unpublished entry. App Details reads **What’s New** and **Version History** from the deployed package manifest, while the Store reads them from the latest published snapshot; unpublished workspace edits must never change the Store page. The manifest also exposes `package.json` `notisAppVersion` as the package version shown in App Details.
|
|
101
|
+
22. **Database rows are private unless explicitly seeded** -- A string declaration such as `databases: ['notes']` publishes schema only and never includes the developer's rows. Use `{ slug: 'templates', seedDocuments: true }` only for small, intentional starter content that every installer should receive. Never enable it for user-created notes, history, leads, or other personal data.
|
|
102
|
+
23. **Public submissions are complete, reviewable packages** -- The registry PR must contain the full editable source tree, Store assets, exact source-declared database schemas, and only explicitly seeded starter rows. Registry CI validates those boundaries before merge; do not hand-edit `notis-listing.json` or strip source files to make a check pass. Fix the app locally, redeploy, and resubmit.
|
|
103
|
+
|
|
104
|
+
## Anti-patterns -- NEVER do these
|
|
105
|
+
|
|
106
|
+
These are the most common mistakes agents make. Each one wastes time and produces broken results.
|
|
107
|
+
|
|
108
|
+
- **NEVER assume app deploys create databases for you** -- Create or update databases through native Notis database tools or the assistant first, then reference them by slug in `notis.config.ts`. Database creation requires the owning app to exist: pass its slug or id in the `app` argument of `LOCAL_NOTIS_DATABASE_UPSERT_DATABASE` (create the app first with `LOCAL_NOTIS_CREATE_APP` if needed). A database can only be referenced by the app that owns it.
|
|
109
|
+
- **NEVER bypass the supported workflow by manually stitching together low-level save or lint calls from a local workspace** -- Local agents should go through the NPX Notis CLI for `apps pull`, `apps dev`, `apps build`, `apps verify`, `apps create`, `apps link`, and `apps deploy`.
|
|
110
|
+
- **NEVER invent a Store clone path** -- `npx --package @notis_ai/cli@latest -- notis apps pull` only pulls source for an app the user can already access as an installed app. Pulling source directly from arbitrary Store listings is not supported yet.
|
|
111
|
+
- **NEVER deploy on your own initiative** -- A clean `apps build` + `apps verify` is NOT a signal to deploy. `apps create` / `apps deploy` install the app onto the user's account; run them only after the user has tested the local (`apps dev`) build and explicitly asked you to deploy. When you finish building, hand off for local testing and stop — do not create or deploy unprompted.
|
|
112
|
+
- **NEVER submit without explicit approval** -- A deploy request alone does not authorize Store submission. Run `npx --package @notis_ai/cli@latest -- notis apps publish --confirm-ready` only when the user confirms App Details is ready for Store review.
|
|
113
|
+
- **NEVER write raw `views/<slug>/index.js` files** -- Write standard React pages in `app/`.
|
|
114
|
+
- **NEVER invent `npx --package @notis_ai/cli@latest -- notis apps push` or bypass the review flow** -- Source moves through `apps pull` and `apps deploy`; `apps publish --confirm-ready` submits the deployed snapshot through the same authenticated review endpoint as App Details.
|
|
115
|
+
- **NEVER treat `apps deploy` as store submission** -- It updates the linked installed app for the current account or team scope only. Store submission is a separate, explicitly confirmed step.
|
|
116
|
+
- **NEVER explore server code or tool schemas to invent an alternative app workflow** -- Use the Notis CLI.
|
|
117
|
+
- **NEVER work around a missing `collection.sidebar` portal tree by rendering a duplicate sidebar inside the app** -- keep the route manifest as the source of truth and escalate the missing portal sidebar as a platform bug instead.
|
|
118
|
+
- **NEVER invent a custom visual language** -- Do not ship full-screen gradients, glassmorphism, bright neon palettes, or raw HTML controls as the primary UI. Apps should look like a natural extension of the portal.
|
|
119
|
+
- **NEVER hand-roll buttons/cards/badges when the scaffold already provides shadcn primitives** -- Prefer `@/components/ui/*` and portal token classes such as `bg-background`, `bg-card`, `border-border`, and `text-muted-foreground`.
|
|
120
|
+
|
|
121
|
+
## Workflow
|
|
122
|
+
|
|
123
|
+
**Default to the bundled scaffold catalog, not a blank project.** Most user requests overlap with one of the scaffolds shipped inside the CLI. Starting from a bundled scaffold is faster than a bare app and does not require backend Store access.
|
|
124
|
+
|
|
125
|
+
1. **Find a starting point.** Run `npx --package @notis_ai/cli@latest -- notis apps scaffolds list`. If something close matches, run `npx --package @notis_ai/cli@latest -- notis apps init "My App" --from <slug>`. Only run plain `npx --package @notis_ai/cli@latest -- notis apps init "My App"` when no scaffold fits.
|
|
126
|
+
2. **Pull only installed apps.** If the user explicitly wants to fork an app they already installed, run `npx --package @notis_ai/cli@latest -- notis apps list`, then `npx --package @notis_ai/cli@latest -- notis apps pull <app-id> ./<dir>`. To fork a Store app that is not installed, tell the user to install it from `/store` first.
|
|
127
|
+
3. **Edit the listing source.** Update `name` (slug), `title`, description, icon, accent, author, categories, tagline, databases, routes, and tools in `notis.config.ts`. Declare a database as a string for schema-only Store packaging; use `{ slug: 'templates', seedDocuments: true }` only when its rows are deliberate starter content for every installer. Keep the complete Store release history in the root `CHANGELOG.md`, newest entry first, using `## [Release title] - YYYY-MM-DD` (or `{PR_MERGE_DATE}` before publication). The first entry powers **What’s New** and the same file powers **Version History**. `icon` is a `phosphor:<name>` value or `metadata/icon.png`; when unset the app shows its **two-letter initials** everywhere (store, sidebar, app details). `accent` optionally pins the avatar color to one of `blue|violet|emerald|amber|rose|sky|fuchsia|teal` (default derived from the app id). Icon/accent flow through deploy onto the app row + listing and can also be set later via the `update_app` tool.
|
|
128
|
+
4. **Build pages in `app/`.** Reuse scaffold code wherever it fits.
|
|
129
|
+
5. **Iterate live.** Run `npx --package @notis_ai/cli@latest -- notis apps dev` so the desktop sidebar's Local development group discovers the app and the Electron Portal renders the local bundle. In the Notis monorepo's supervised `dev.sh` stack, keep app projects under `apps/<slug>/`; the root supervisor discovers that directory, owns the long-running process, and restarts it. A root-level app folder is not supervised and can disappear as soon as an agent-owned terminal exits.
|
|
130
|
+
6. **Capture listing screenshots.** Declare 3–6 screenshots in `notis.config.ts`, each with a stable `path`, descriptive `alt`, and optional `route`/`scenario`/`focus`/`theme`, then run `npx --package @notis_ai/cli@latest -- notis apps screenshot`. Use `focus` to frame a real app root without empty browser canvas; use `theme: 'light'` or `theme: 'dark'` to match both the Portal render and Store backdrop, and pair both modes when that best represents the app. It renders the configured states in a headless harness and writes exact 2000x1250 PNGs under `metadata/`, using the deterministic Store presentation by default (`--raw` is diagnostic only). Apps are icon-led like Raycast — the icon set in `notis.config.ts` represents the app, so there is no cover image, only these screenshots. Never hand-author the PNGs; regenerate them when routes or UI change.
|
|
131
|
+
7. **Verify locally.** Run `npm install`, then `npx --package @notis_ai/cli@latest -- notis apps build` and `npx --package @notis_ai/cli@latest -- notis apps verify`. Surface the verify report and fix failures.
|
|
132
|
+
8. **Local-development-first handoff — STOP HERE.** Keep `apps dev` running and hand off to the user: tell them the app is live in the desktop **Local development** sidebar group (green `DEV` badge) and ask them to test it there. Building a new app to this point, without deploying, is a **complete and expected** result. Do NOT proceed to `apps create` / `apps deploy` yet — wait for the user to test and explicitly ask to deploy. (`apps dev` is what puts the app in Local development; without a running session the app never appears there.) **Before handing off, complete all three acceptance checks:**
|
|
133
|
+
1. Registry: `cat "$CONDUCTOR_WORKSPACE_PATH/.context/app-dev-sessions.json"` lists the app's `devSlug` with a fresh `lastHeartbeatAt`. If it is absent (the session landed in global `~/.notis` instead), restart with `NOTIS_APP_DEV_SESSIONS_FILE="$CONDUCTOR_WORKSPACE_PATH/.context/app-dev-sessions.json"`.
|
|
134
|
+
2. Bundle: the session's loopback `/snapshot` URL responds successfully and contains the expected manifest/routes.
|
|
135
|
+
3. Mount acknowledgment: capture the current `apps dev` status `Mounted in Notis: <app name>`. This is the deterministic proof that the nonce-backed session reached the Portal's final Local development sidebar model. If the CLI says only `Serving locally`, do not claim the app is mounted. Manual Electron rendering is optional here; use it when the task specifically requires UI/behavior verification, not as the mount handshake.
|
|
136
|
+
See Troubleshooting → *App is missing from Local development* if any check fails.
|
|
137
|
+
9. **Deploy only when the user asks.** Once the user has tested locally and explicitly requests a deploy, run `npx --package @notis_ai/cli@latest -- notis apps create "<name>" .` (first time) then `npx --package @notis_ai/cli@latest -- notis apps deploy --direct`, or link first with `npx --package @notis_ai/cli@latest -- notis apps link <id> .` / pass `--app-id <id>` for an existing app. Deploy installs or updates the app on the user's account (it appears under **Workspace**, not Local development). After first install, `.notis/state.json` must point at the installed app id so future local-dev actions become **Update**, not another **Install**.
|
|
138
|
+
10. **Submit only after confirmation.** When the user explicitly confirms the current App Details page is ready, ensure the approved state is deployed, then run `npx --package @notis_ai/cli@latest -- notis apps publish --confirm-ready`. The command submits Team apps immediately or opens the Public Store registry review PR. Without that confirmation, stop after deploy.
|
|
139
|
+
|
|
140
|
+
### Quick start
|
|
141
|
+
|
|
142
|
+
Steps 1–3 are the agent's job on a build request. Step 4 is **user-gated** — do not run it until the user has tested the local build and asked you to deploy.
|
|
24
143
|
|
|
25
144
|
```bash
|
|
26
|
-
|
|
145
|
+
# 1. Pick a scaffold and scaffold
|
|
146
|
+
npx --package @notis_ai/cli@latest -- notis apps scaffolds list
|
|
147
|
+
npx --package @notis_ai/cli@latest -- notis apps init "My App" --from <scaffold-slug>
|
|
148
|
+
cd my-app
|
|
149
|
+
npm install
|
|
150
|
+
|
|
151
|
+
# 2. Develop against the Electron Portal, then HAND OFF for the user to test.
|
|
152
|
+
# Keep this running — it is what surfaces the app in the Local development
|
|
153
|
+
# sidebar group. This is the finish line for a build request.
|
|
27
154
|
npx --package @notis_ai/cli@latest -- notis apps dev
|
|
155
|
+
# ... iterate until the app looks right in the Local development sidebar group ...
|
|
156
|
+
|
|
157
|
+
# 3. Build, capture listing screenshots, and verify (still local — no deploy)
|
|
28
158
|
npx --package @notis_ai/cli@latest -- notis apps build
|
|
29
159
|
npx --package @notis_ai/cli@latest -- notis apps screenshot
|
|
30
160
|
npx --package @notis_ai/cli@latest -- notis apps verify
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
npx --package @notis_ai/cli@latest -- notis apps
|
|
161
|
+
|
|
162
|
+
# 4. ONLY after the user tested locally and asked to deploy: create + deploy.
|
|
163
|
+
# This writes .notis/state.json so future deploys update this app.
|
|
164
|
+
npx --package @notis_ai/cli@latest -- notis apps create "My App" .
|
|
165
|
+
npx --package @notis_ai/cli@latest -- notis apps deploy --direct
|
|
166
|
+
|
|
167
|
+
# 5. ONLY after the user explicitly confirms App Details is ready for Store review
|
|
35
168
|
npx --package @notis_ai/cli@latest -- notis apps publish --confirm-ready
|
|
36
|
-
npx --package @notis_ai/cli@latest -- notis apps doctor
|
|
37
169
|
```
|
|
38
170
|
|
|
39
|
-
|
|
171
|
+
If deploying to an existing app without linking first, pass `--app-id` directly. Prefer linking when this checkout will keep being used for development:
|
|
40
172
|
|
|
41
173
|
```bash
|
|
42
|
-
npx --package @notis_ai/cli@latest -- notis apps
|
|
174
|
+
npx --package @notis_ai/cli@latest -- notis apps link <app-id> .
|
|
175
|
+
npx --package @notis_ai/cli@latest -- notis apps deploy --direct --app-id <app-id>
|
|
43
176
|
```
|
|
44
177
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Use React + Vite only. Do not use Next.js or a custom server for app projects.
|
|
48
|
-
- Build standard pages in `app/`. Do not write raw `views/<slug>/index.js` files.
|
|
49
|
-
- Keep navigation in `notis.config.ts` `routes`; each route needs a stable `slug`.
|
|
50
|
-
- Reference existing databases by slug in `notis.config.ts`; do not assume deploy creates databases automatically.
|
|
51
|
-
- Every native database is owned by exactly one app. Creating one with `LOCAL_NOTIS_DATABASE_UPSERT_DATABASE` requires the owning app's slug or id in the `app` argument (create the app first with `LOCAL_NOTIS_CREATE_APP` if needed); deleting an app deletes its databases and their documents.
|
|
52
|
-
- Declare runtime tool access in `notis.config.ts` `tools`.
|
|
53
|
-
- Use `@notis/sdk` hooks instead of direct runtime access.
|
|
54
|
-
- Do not rely on `window.__NOTIS_RUNTIME__` or portal-owned DOM hooks.
|
|
55
|
-
- `npx --package @notis_ai/cli@latest -- notis apps deploy` updates an installed app. It does not publish to the public App Store.
|
|
56
|
-
- **Local development first; deploy is user-gated.** Iterate with `apps dev` and hand off for the **user** to test in the desktop **Local development** sidebar group. Do not run `apps create` / `apps deploy` on your own — a clean build/verify is not permission to deploy. Deploy only when the user has tested the local build and explicitly asks. Finishing a build without deploying is the expected outcome.
|
|
57
|
-
- **Installed app links are explicit.** A mounted dev session updates an installed app only when the checkout is linked by app id in `.notis/state.json` and the active dev-session registry mirrors that id. Name or slug matches may be suggestions, never update targets.
|
|
58
|
-
- **Store submission is separately user-gated.** Run `apps publish --confirm-ready` only after the user explicitly confirms the current App Details page is ready. Deploy that exact approved state first; never infer Store approval from a deploy request.
|
|
59
|
-
- **Bump `notisAppVersion` for every Store update.** `package.json` must contain a semver `notisAppVersion`; increment it beyond the currently published registry version before deploying an update.
|
|
60
|
-
- **Keep release history in one root `CHANGELOG.md`.** Put the newest entry first and use `## [Release title] - YYYY-MM-DD`, or `{PR_MERGE_DATE}` before publication. Do not add new `versionNotes` fields to `notis.config.ts`. App Details reads **What’s New** and **Version History** from the deployed package manifest; the Store reads the latest published snapshot, so unpublished workspace edits never change it. The manifest exposes `package.json` `notisAppVersion` as the package version shown in App Details.
|
|
61
|
-
- Public submissions still use the registry review flow; the CLI invokes the same authenticated submission endpoint as App Details.
|
|
62
|
-
- Use Phosphor icon names with the `phosphor:` prefix. Do not use emoji icons.
|
|
63
|
-
- Prefer scaffolded shadcn components and portal theme tokens over custom visual systems.
|
|
64
|
-
|
|
65
|
-
## App Workflow
|
|
66
|
-
|
|
67
|
-
1. Discover existing apps if needed:
|
|
178
|
+
Or if editing an installed app:
|
|
68
179
|
|
|
69
180
|
```bash
|
|
70
181
|
npx --package @notis_ai/cli@latest -- notis apps list
|
|
182
|
+
npx --package @notis_ai/cli@latest -- notis apps pull <installed-app-id> ./my-app
|
|
183
|
+
cd my-app
|
|
184
|
+
npm install
|
|
185
|
+
npx --package @notis_ai/cli@latest -- notis apps dev
|
|
186
|
+
npx --package @notis_ai/cli@latest -- notis apps build
|
|
187
|
+
npx --package @notis_ai/cli@latest -- notis apps verify
|
|
188
|
+
npx --package @notis_ai/cli@latest -- notis apps deploy --direct --app-id <existing-app-id>
|
|
71
189
|
```
|
|
72
190
|
|
|
73
|
-
|
|
191
|
+
## Building an App
|
|
74
192
|
|
|
75
|
-
|
|
76
|
-
npx --package @notis_ai/cli@latest -- notis apps scaffolds list
|
|
77
|
-
npx --package @notis_ai/cli@latest -- notis apps init "My App"
|
|
78
|
-
npx --package @notis_ai/cli@latest -- notis apps pull <app-id> ./my-app
|
|
79
|
-
```
|
|
193
|
+
### Step 1: Define the config
|
|
80
194
|
|
|
81
|
-
|
|
195
|
+
Create `notis.config.ts` with:
|
|
196
|
+
- **name** -- Display name
|
|
197
|
+
- **databases** -- Slug references to existing Notis databases
|
|
198
|
+
- **routes** -- Route-first sidebar entries with explicit `slug`, optional `parentSlug`, and optional `collection.sidebar` tree config
|
|
199
|
+
- **tools** -- Tool names the app can call at runtime
|
|
82
200
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
201
|
+
For collection-backed sidebars, use the route schema directly:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
routes: [
|
|
205
|
+
{
|
|
206
|
+
path: '/',
|
|
207
|
+
slug: 'notes',
|
|
208
|
+
name: 'Notes',
|
|
209
|
+
icon: 'phosphor:note-pencil',
|
|
210
|
+
default: true,
|
|
211
|
+
collection: {
|
|
212
|
+
database: 'notes',
|
|
213
|
+
titleProperty: 'Title',
|
|
214
|
+
parentProperty: 'Parent note',
|
|
215
|
+
sidebar: {
|
|
216
|
+
mode: 'tree',
|
|
217
|
+
allowCreate: true,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
]
|
|
86
222
|
```
|
|
87
223
|
|
|
88
|
-
|
|
224
|
+
Use the same page template for the root Notes route and collection/sub-collection detail states. The portal sidebar injects live collection items under the static route row when `collection.sidebar.mode === 'tree'`.
|
|
89
225
|
|
|
90
|
-
|
|
226
|
+
### Step 2: Build pages
|
|
91
227
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
228
|
+
Standard React pages in `app/`. Use generic SDK tool hooks for data and build on top of the scaffolded shadcn components and portal shell classes (`notis-app-shell`, `notis-app-surface`):
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
'use client';
|
|
232
|
+
import { useEffect, useState } from 'react';
|
|
233
|
+
import { useTool } from '@notis/sdk';
|
|
234
|
+
import { Card } from '@/components/ui/card';
|
|
235
|
+
|
|
236
|
+
type QueryTasksArgs = { database_id?: string; database_slug?: string; query: { page_size?: number } };
|
|
237
|
+
type TaskDoc = { document_id?: string; id?: string; title?: string; properties?: Record<string, unknown> };
|
|
238
|
+
type QueryTasksResult = { documents?: TaskDoc[] };
|
|
239
|
+
|
|
240
|
+
export default function TasksPage() {
|
|
241
|
+
const queryTasks = useTool<QueryTasksArgs, QueryTasksResult>('LOCAL_NOTIS_DATABASE_QUERY');
|
|
242
|
+
const [documents, setDocuments] = useState<TaskDoc[]>([]);
|
|
243
|
+
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
void queryTasks
|
|
246
|
+
.call({ database_id: 'tasks-db-id', query: { page_size: 25 } })
|
|
247
|
+
.then((result) => setDocuments(result.documents || []));
|
|
248
|
+
}, [queryTasks.call]);
|
|
249
|
+
|
|
250
|
+
if (queryTasks.loading) return <div>Loading...</div>;
|
|
251
|
+
|
|
252
|
+
return (
|
|
253
|
+
<div className="p-6 space-y-4">
|
|
254
|
+
{documents.map((doc) => (
|
|
255
|
+
<Card key={doc.id || doc.document_id} className="p-4">
|
|
256
|
+
<h3>{doc.title || 'Untitled'}</h3>
|
|
257
|
+
<p className="text-muted-foreground">{String(doc.properties?.status || '')}</p>
|
|
258
|
+
</Card>
|
|
259
|
+
))}
|
|
260
|
+
</div>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
96
263
|
```
|
|
97
264
|
|
|
98
|
-
|
|
99
|
-
`alt`, and optional `route`/`scenario`/`focus`/`theme`. Use `focus` to crop to a
|
|
100
|
-
real app root instead of empty browser canvas, and use `theme: 'light'` or
|
|
101
|
-
`theme: 'dark'` for a matching Portal render and Store frame. Paired light/dark
|
|
102
|
-
entries may reuse the same route and scenario. `notis apps screenshot` renders
|
|
103
|
-
those configured states in a headless harness and writes exact 2000x1250 PNGs
|
|
104
|
-
under `metadata/`, using the deterministic Store presentation by default. Use
|
|
105
|
-
`--raw` only for an unframed diagnostic capture. Apps are icon-led like Raycast:
|
|
106
|
-
the app icon represents the app everywhere, so there is no cover image — only
|
|
107
|
-
these screenshots. Re-run after changing routes or UI; it overwrites the set and
|
|
108
|
-
drops stale files. Use `--routes home,history` to capture a subset.
|
|
265
|
+
### Discovering database schema
|
|
109
266
|
|
|
110
|
-
|
|
267
|
+
Before writing app code, inspect the database schema to know what properties exist:
|
|
111
268
|
|
|
112
269
|
```bash
|
|
113
|
-
npx --package @notis_ai/cli@latest -- notis
|
|
114
|
-
npx --package @notis_ai/cli@latest -- notis
|
|
270
|
+
npx --package @notis_ai/cli@latest -- notis tools search "list Notis databases"
|
|
271
|
+
npx --package @notis_ai/cli@latest -- notis tools exec LOCAL_NOTIS_DATABASE_LIST_DATABASES --arguments '{}'
|
|
272
|
+
npx --package @notis_ai/cli@latest -- notis tools exec LOCAL_NOTIS_DATABASE_GET_DATABASE --arguments '{"database_slug":"social_media_calendar"}'
|
|
273
|
+
npx --package @notis_ai/cli@latest -- notis tools exec LOCAL_NOTIS_DATABASE_QUERY --arguments '{"database_id":"social-media-calendar-db-id","query":{"page_size":1}}'
|
|
115
274
|
```
|
|
116
275
|
|
|
117
|
-
|
|
276
|
+
Prefer the database `id` returned by `LOCAL_NOTIS_DATABASE_LIST_DATABASES` or `LOCAL_NOTIS_DATABASE_GET_DATABASE` when calling `LOCAL_NOTIS_DATABASE_QUERY`; use `database_slug` only as a fallback.
|
|
118
277
|
|
|
119
|
-
|
|
120
|
-
|
|
278
|
+
Use `LOCAL_NOTIS_DATABASE_GET_DATABASE` through `useTool` when an app needs schema detail at runtime. Keep database-specific result and property helper types inside the app code.
|
|
279
|
+
For document writes, declare the generated canonical tool for the target database, such as `LOCAL_NOTIS_DATABASE_UPSERT_TASKS`, and call it through `useTool`. Pass flat property values; the server wraps them:
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
const upsertTask = useTool<Record<string, unknown>, { document?: { id: string } }>('LOCAL_NOTIS_DATABASE_UPSERT_TASKS');
|
|
283
|
+
|
|
284
|
+
await upsertTask.call({
|
|
285
|
+
title: 'My Task',
|
|
286
|
+
Status: 'Todo',
|
|
287
|
+
Priority: 'P1',
|
|
288
|
+
Due: '2025-04-01',
|
|
289
|
+
Done: false,
|
|
290
|
+
Count: 5,
|
|
291
|
+
});
|
|
121
292
|
```
|
|
122
293
|
|
|
123
|
-
|
|
294
|
+
Do NOT pass Notion-style wrappers (`{select: {name: "Todo"}}`) when upserting.
|
|
124
295
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
296
|
+
### Design rules
|
|
297
|
+
|
|
298
|
+
- Start from the scaffolded `@/components/ui/*` components before writing new UI primitives.
|
|
299
|
+
- Use restrained portal surfaces: `bg-background`, `bg-card`, `border-border`, `text-foreground`, `text-muted-foreground`.
|
|
300
|
+
- Keep layouts compact and dashboard-like. Prefer cards, sections, badges, and tables over marketing-style hero treatments.
|
|
301
|
+
- Respect the portal theme. Do not hardcode dark mode or create an app-specific palette.
|
|
302
|
+
- If a screen looks like a standalone microsite instead of a portal tool, it is too custom.
|
|
303
|
+
- For Notes-style apps, the folder tree belongs to the portal sidebar when configured via `collection.sidebar`. The page content should complement that chrome, not duplicate or replace it.
|
|
304
|
+
- Never indicate selected items with a heavy left-border bar (e.g. `border-l-2 border-l-foreground` paired with a muted background). It looks dated and clashes with the portal chrome. Use a single subtle background change (`bg-muted` for selected, `hover:bg-muted/50` for hover) and let typography or an icon carry the rest of the state.
|
|
305
|
+
- Do not render any search input inside the app (in-page search rails, "Ask Notis…" pills, command-palette-style bars, etc.). The portal already owns the top-bar search field. Wire your view to it with `useTopBarSearch({ value, onChange, placeholder, onSubmit })` from `@notis/sdk` and let the page filter or refetch on the values it receives. The hook also exposes `setLoading` so the standard top-bar spinner reflects in-flight queries.
|
|
306
|
+
|
|
307
|
+
### Sidebar invariants
|
|
308
|
+
|
|
309
|
+
- When a user asks for folders, sections, or hierarchy in the app sidebar, express that through `routes` and `collection.sidebar` in `notis.config.ts`.
|
|
310
|
+
- Treat an existing collection-tree sidebar as a locked structural requirement unless the user explicitly asks to change navigation architecture.
|
|
311
|
+
- If the sidebar appears missing in the Local development sidebar group or deployed portal build, do not silently redesign around it. Preserve the manifest contract, call out the discrepancy, and treat it as a portal/runtime bug.
|
|
312
|
+
|
|
313
|
+
### Step 3: Root layout
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { NotisProvider } from '@notis/sdk';
|
|
317
|
+
import '@notis/sdk/styles.css';
|
|
318
|
+
import './globals.css';
|
|
319
|
+
|
|
320
|
+
export default function AppShell({ children }: { children: React.ReactNode }) {
|
|
321
|
+
return <NotisProvider>{children}</NotisProvider>;
|
|
322
|
+
}
|
|
128
323
|
```
|
|
129
324
|
|
|
130
|
-
##
|
|
325
|
+
## Manifest Format
|
|
131
326
|
|
|
132
|
-
|
|
327
|
+
Generated by `npx --package @notis_ai/cli@latest -- notis apps build` at `.notis/output/manifest.json`:
|
|
133
328
|
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
app
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"version": 1,
|
|
332
|
+
"spec_version": 4,
|
|
333
|
+
"app": { "name": "My App", "description": "...", "icon": "phosphor:..." },
|
|
334
|
+
"routes": [
|
|
335
|
+
{
|
|
336
|
+
"path": "/",
|
|
337
|
+
"slug": "index",
|
|
338
|
+
"name": "Dashboard",
|
|
339
|
+
"icon": "phosphor:squares-four",
|
|
340
|
+
"default": true,
|
|
341
|
+
"export_name": "index",
|
|
342
|
+
"collection": null
|
|
343
|
+
}
|
|
344
|
+
],
|
|
345
|
+
"bundle": {
|
|
346
|
+
"js": "bundle/app.js",
|
|
347
|
+
"css": "bundle/app.css"
|
|
348
|
+
},
|
|
349
|
+
"databases": ["tasks", { "slug": "templates", "seed_documents": true }],
|
|
350
|
+
"tools": ["LOCAL_NOTIS_DATABASE_QUERY"]
|
|
351
|
+
}
|
|
142
352
|
```
|
|
143
353
|
|
|
144
|
-
`
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
354
|
+
Use canonical `notis-*` tool names for explicit app tool declarations. App-specific TypeScript shapes for tool arguments and results live in the app code; the SDK exposes the generic `useTool<TArgs, TResult>()` hook instead of database-specific tool hooks.
|
|
355
|
+
|
|
356
|
+
Database strings package schema only. The object form shown above opts that database into copying its current rows as Store starter content. Use it sparingly and only for non-personal fixtures/templates every installer is meant to receive.
|
|
357
|
+
|
|
358
|
+
For a read-only database catalog app, declare `["LOCAL_NOTIS_DATABASE_LIST_DATABASES", "LOCAL_NOTIS_DATABASE_GET_DATABASE"]`. Use the list tool for the left/catalog pane and the get tool for the selected database detail pane.
|
|
359
|
+
|
|
360
|
+
## Database Schema
|
|
361
|
+
|
|
362
|
+
### apps table
|
|
363
|
+
|
|
364
|
+
| Column | Type | Description |
|
|
365
|
+
|---|---|---|
|
|
366
|
+
| id | uuid PK | App ID |
|
|
367
|
+
| user_id | uuid FK | Owner |
|
|
368
|
+
| team_id | uuid FK | Team (nullable) |
|
|
369
|
+
| name | text | Display name |
|
|
370
|
+
| slug | text UNIQUE | URL slug |
|
|
371
|
+
| description | text | App description |
|
|
372
|
+
| icon | text | Phosphor icon (e.g. "phosphor:list") |
|
|
373
|
+
| status | text | draft, active, archived |
|
|
374
|
+
| visibility | text | private, team |
|
|
375
|
+
| manifest | jsonb | Latest deployed manifest |
|
|
376
|
+
| current_version | integer | Version counter |
|
|
377
|
+
| source_listing_id | uuid FK | Source App Store listing for installed store apps; cleared when submitted as a derivative |
|
|
378
|
+
| installed_snapshot | jsonb | Store-installed baseline used for update/reset comparison |
|
|
379
|
+
| customization_overlay | jsonb | User changes over the installed store baseline |
|
|
380
|
+
| update_status | text | up_to_date, update_available, needs_resolution, update_failed |
|
|
381
|
+
| bundled_automation_ids | uuid[] | Linked automations |
|
|
382
|
+
| bundled_skill_ids | uuid[] | Linked skills |
|
|
383
|
+
|
|
384
|
+
### databases ownership
|
|
385
|
+
|
|
386
|
+
Every row in the `databases` table carries `owner_app_id` (uuid FK to
|
|
387
|
+
`apps.id`, `ON DELETE CASCADE`): a database belongs to exactly one app, and
|
|
388
|
+
deleting the app deletes its databases and their documents (`documents` cascade
|
|
389
|
+
from `databases`). Install, dev materialization, and store updates stamp
|
|
390
|
+
`owner_app_id` automatically; standalone creation requires the `app` argument.
|
|
391
|
+
|
|
392
|
+
### Storage (Supabase)
|
|
393
|
+
|
|
394
|
+
Files stored in `app-code` bucket at `{app_id}/v{version}/`:
|
|
395
|
+
- `manifest.json`
|
|
396
|
+
- `bundle/app.js`
|
|
397
|
+
- `bundle/app.css`
|
|
398
|
+
|
|
399
|
+
Editable source snapshots are stored in the private `app-source` bucket at
|
|
400
|
+
`{app_id}/v{version}/`. Portal App Store listing screenshots are uploaded to
|
|
401
|
+
the public `app-listing-assets` bucket before submission.
|
|
402
|
+
|
|
403
|
+
### Related tables
|
|
404
|
+
|
|
405
|
+
- **databases** -- Apps reference these rows by slug. Schema lives on the database row (`schema_metadata` / `original_fields`), not in the app manifest.
|
|
406
|
+
- **documents** -- `database_id` links to databases. Properties in `properties` jsonb.
|
|
407
|
+
- **app_store_listings** -- Snapshots for publishing to the app store.
|
|
408
|
+
- **app_submissions** -- Portal review submissions keyed to an app source version and registry slug.
|
|
409
|
+
|
|
410
|
+
## Server Endpoints
|
|
411
|
+
|
|
412
|
+
| Endpoint | Method | Purpose |
|
|
413
|
+
|---|---|---|
|
|
414
|
+
| `/portal_views/get` | GET | Route detail + runtime descriptor with signed bundle URLs |
|
|
415
|
+
| `/portal_views/runtime_query` | POST | Proxy tool calls and DB operations |
|
|
416
|
+
| `/portal_views/collection_items` | GET | List collection items |
|
|
417
|
+
| `/portal_views/collection_tree` | GET | List normalized collection tree nodes for a tree sidebar route |
|
|
418
|
+
| `/portal_views/collection_tree/create` | POST | Create a root or child collection row from the sidebar |
|
|
419
|
+
| `/portal_views/collection_tree/rename` | POST | Rename a collection tree item inline |
|
|
420
|
+
| `/portal_views/collection_tree/delete` | POST | Delete a collection tree item from the sidebar |
|
|
421
|
+
| `/portal_apps/list` | GET | List apps |
|
|
422
|
+
| `/portal_apps/get` | GET | Get app detail |
|
|
423
|
+
| `/portal_apps/publish` | POST | Submit a deployed app source snapshot for public store review |
|
|
424
|
+
| `/portal_apps/listing_assets/upload` | POST | Legacy pre-manifest screenshot upload; do not use for current manifest-media workflows |
|
|
425
|
+
| `/portal_apps/submissions` | GET/PATCH | List or edit App Store submissions |
|
|
426
|
+
| `/portal_apps/submissions/withdraw` | POST | Close a pending App Store submission |
|
|
427
|
+
| `/cli_tools` | POST | CLI tool execution (save_app_files, create_app, etc.) |
|
|
428
|
+
|
|
429
|
+
## SDK Hook Reference
|
|
430
|
+
|
|
431
|
+
All hooks are imported from `@notis/sdk`:
|
|
432
|
+
|
|
433
|
+
| Hook | Signature | Description |
|
|
434
|
+
|------|-----------|-------------|
|
|
435
|
+
| `useNotis()` | `() => { app, route, context, ready }` | App metadata, current route, generic portal context, ready state |
|
|
436
|
+
| `useTool<TArgs, TResult>(name)` | `(name: string) => { call, loading, error }` | Call a specific tool by name with app-defined argument and result types |
|
|
437
|
+
| `useTools()` | `() => { tools, loading }` | List available tools |
|
|
438
|
+
| `useNotisNavigation()` | `() => { toRoute, toDocument, toApp }` | Navigate between routes, documents, or the app root |
|
|
439
|
+
| `useTopBarSearch(opts)` | `({ value, onChange, placeholder?, onSubmit? }) => { setLoading }` | Bind the current view to the Portal-owned top-bar search input |
|
|
440
|
+
| `useBackend()` | `() => { request }` | Raw backend request proxy with JWT auth |
|
|
441
|
+
|
|
442
|
+
### Typed tool calls
|
|
443
|
+
|
|
444
|
+
`useTool` accepts generic argument and result types. Query the database at dev time to discover actual property shapes, then keep those types in the app:
|
|
149
445
|
|
|
150
|
-
|
|
446
|
+
```tsx
|
|
447
|
+
type QueryTasksArgs = { database_id?: string; database_slug?: string; query: { page_size?: number } };
|
|
448
|
+
interface TaskDoc {
|
|
449
|
+
title: string;
|
|
450
|
+
properties: {
|
|
451
|
+
Status: string;
|
|
452
|
+
Priority: string;
|
|
453
|
+
Due: string;
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
type QueryTasksResult = { documents: TaskDoc[] };
|
|
457
|
+
|
|
458
|
+
const queryTasks = useTool<QueryTasksArgs, QueryTasksResult>('LOCAL_NOTIS_DATABASE_QUERY');
|
|
459
|
+
const result = await queryTasks.call({ database_id: 'tasks-db-id', query: { page_size: 25 } });
|
|
460
|
+
// result.documents[0].properties.Status is typed as string
|
|
461
|
+
```
|
|
151
462
|
|
|
152
|
-
|
|
153
|
-
- listing screenshots: stable path, alt text, and optional capture route/scenario/focus/theme
|
|
154
|
-
- database slug references
|
|
155
|
-
- route definitions
|
|
156
|
-
- tool access
|
|
463
|
+
## Development Modes
|
|
157
464
|
|
|
158
|
-
|
|
465
|
+
### Canonical local development
|
|
159
466
|
|
|
160
|
-
```
|
|
161
|
-
|
|
467
|
+
```bash
|
|
468
|
+
npx --package @notis_ai/cli@latest -- notis apps dev
|
|
469
|
+
```
|
|
162
470
|
|
|
163
|
-
|
|
471
|
+
Runs the real desktop-local development workflow. The CLI should discover all apps in the target workspace, serve their bundles from loopback, and surface them in the Electron Portal's Local development sidebar group through the local desktop session registry.
|
|
164
472
|
|
|
165
|
-
|
|
473
|
+
## Deploy Without Backend Server
|
|
166
474
|
|
|
167
|
-
|
|
475
|
+
If the backend server at `localhost:3001` is not running, use `--direct`:
|
|
168
476
|
|
|
169
|
-
|
|
477
|
+
```bash
|
|
478
|
+
npx --package @notis_ai/cli@latest -- notis apps deploy --direct
|
|
170
479
|
```
|
|
171
480
|
|
|
172
|
-
|
|
173
|
-
valid entry. Ordinary local development and deployment still work when an app
|
|
174
|
-
is not being prepared for the Store.
|
|
481
|
+
This uploads the bundle and editable source snapshot directly to Supabase storage and updates the app manifest in the database, bypassing the backend server entirely. The CLI auto-falls back to direct mode on network errors.
|
|
175
482
|
|
|
176
|
-
|
|
483
|
+
## Testing
|
|
177
484
|
|
|
178
|
-
|
|
485
|
+
1. **Build validation**: `npx --package @notis_ai/cli@latest -- notis apps build` must succeed without errors. Vite surfaces TypeScript and bundling errors during this step.
|
|
486
|
+
2. **Headless render verification** (recommended after every build): run `npx --package @notis_ai/cli@latest -- notis apps verify`. It builds unless `--skip-build` is passed, spins up a loopback harness, drives `agent-browser` against every route, and reports per-route pass/fail with captured render errors and runtime calls.
|
|
487
|
+
3. **Local development acceptance**: Require the running CLI to report `Mounted in Notis`, which proves the exact nonce-backed session entered the current Electron Portal's final `Local development` sidebar model. Registry presence and bundle HTTP health alone prove only `Serving locally`. Opening the default route, asserting shadow-root content, and exercising hot reload remain the right checks when the task includes UI, runtime behavior, or visual acceptance, but they are not required merely to prove mounting.
|
|
488
|
+
4. **Post-deploy**: Verify the deployed bundle via `/portal_views/get` -> `runtime_descriptor.bundle.js_url`, then verify the app renders in the portal. The portal renders app bundles directly as React components, so the fastest verification is navigating to the app page in the portal.
|
|
179
489
|
|
|
180
|
-
|
|
181
|
-
import { defineNotisApp } from '@notis/sdk/config';
|
|
182
|
-
|
|
183
|
-
export default defineNotisApp({
|
|
184
|
-
name: 'my-app',
|
|
185
|
-
title: 'My App',
|
|
186
|
-
description: 'A focused Notis app.',
|
|
187
|
-
icon: 'phosphor:squares-four',
|
|
188
|
-
accent: 'blue',
|
|
189
|
-
databases: ['tasks'],
|
|
190
|
-
routes: [
|
|
191
|
-
{
|
|
192
|
-
path: '/',
|
|
193
|
-
slug: 'tasks',
|
|
194
|
-
name: 'Tasks',
|
|
195
|
-
icon: 'phosphor:check-square',
|
|
196
|
-
default: true,
|
|
197
|
-
},
|
|
198
|
-
],
|
|
199
|
-
tools: ['LOCAL_NOTIS_DATABASE_QUERY', 'LOCAL_NOTIS_DATABASE_UPSERT_TASKS'],
|
|
200
|
-
});
|
|
201
|
-
```
|
|
490
|
+
### Headless harness verification
|
|
202
491
|
|
|
203
|
-
|
|
492
|
+
Run `npx --package @notis_ai/cli@latest -- notis apps verify` after `npx --package @notis_ai/cli@latest -- notis apps build`. Use `--mode live` after deploy to exercise the real `/portal_views/runtime_query` with the CLI JWT instead of stub data. If `agent-browser` is unavailable, pass `--no-browser` to print URLs and use `--keep-open` for interactive triage with `notis-browser-control`.
|
|
204
493
|
|
|
205
|
-
|
|
494
|
+
#### What the harness catches that `npx --package @notis_ai/cli@latest -- notis apps build` does not
|
|
206
495
|
|
|
207
|
-
|
|
208
|
-
|
|
496
|
+
- Hooks that mount but throw on first read (`useTool` called with the wrong tool name or argument shape, accessing nested props that are undefined).
|
|
497
|
+
- Runtime database queries whose slug is not declared by the app, and collection routes that never query their configured collection database. Declared databases may also support automations or agent workflows, so ordinary routes do not need to query every app database.
|
|
498
|
+
- Tool names referenced by hooks but missing from `notis.config.ts -> tools`.
|
|
499
|
+
- Suspense / async boundaries that never resolve because a runtime stub returned the wrong shape.
|
|
500
|
+
- Render-time exceptions that the portal would surface as the `View crashed` error boundary.
|
|
209
501
|
|
|
210
|
-
|
|
211
|
-
```
|
|
502
|
+
#### What the harness does not catch
|
|
212
503
|
|
|
213
|
-
|
|
504
|
+
- Bugs that only manifest with real backend data (auth-scoped filters, RLS, malformed prod records). For those, swap the stub runtime for a real one that posts to `/portal_views/runtime_query` with a JWT.
|
|
505
|
+
- Visual regressions (use `agent-browser screenshot` + a baseline compare if you need this).
|
|
506
|
+
- Bugs that depend on the portal's shadow-DOM stylesheet wrapping. The harness mounts in light DOM, so global Tailwind/shadcn classes work normally; portal-specific theme tokens injected as inline styles are not present.
|
|
214
507
|
|
|
215
508
|
## Troubleshooting
|
|
216
509
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
-
|
|
220
|
-
-
|
|
510
|
+
### Common issues
|
|
511
|
+
|
|
512
|
+
- **Deploy fails with network error**: Backend server not running. Use `npx --package @notis_ai/cli@latest -- notis apps deploy --direct` or start the server.
|
|
513
|
+
- **App shows old code after deploy**: Bundle cache is stale. Hard refresh (Cmd+Shift+R) or clear site data in DevTools.
|
|
514
|
+
- **App is missing from Local development**: First confirm the app lives in the directory owned by the long-running supervisor (`apps/<slug>/` in the Notis monorepo), the current worktree's Electron app is running, and `npx --package @notis_ai/cli@latest -- notis apps dev` is bound to loopback. Then check the **dev-session registry**: `apps dev` records its session in a JSON registry the desktop polls, and the desktop reads a **per-workspace** file at `<workspace>/.context/app-dev-sessions.json` (it sets `NOTIS_APP_DEV_SESSIONS_FILE` on its own runs). An agent-launched `apps dev` that does not resolve that file writes to the global `~/.notis/app-dev-sessions.json` instead — the bundle serves fine but the app never shows in that workspace's sidebar. Verify your session is in the workspace file:
|
|
515
|
+
```bash
|
|
516
|
+
cat "$CONDUCTOR_WORKSPACE_PATH/.context/app-dev-sessions.json" # your devSlug must be present with a fresh lastHeartbeatAt
|
|
517
|
+
```
|
|
518
|
+
If it is missing, restart `apps dev` pointed at that file:
|
|
519
|
+
```bash
|
|
520
|
+
NOTIS_APP_DEV_SESSIONS_FILE="$CONDUCTOR_WORKSPACE_PATH/.context/app-dev-sessions.json" \
|
|
521
|
+
npx --package @notis_ai/cli@latest -- notis apps dev --no-open
|
|
522
|
+
```
|
|
523
|
+
Current CLI auto-resolves the nearest `.context` registry, so the explicit env is only a fallback for older CLIs. Startup and heartbeat preserve other sessions, so this coexists with the desktop's own dev sessions. If the registry row has a `targetAppId`, that id must resolve to an installed app whose manifest is not `is_dev: true`; never repair this by linking to another development-runtime id. Restart the current CLI and let it clear stale hidden/deleted targets automatically. Then wait for `Mounted in Notis`; Electron writes the matching nonce acknowledgment beside the registry only after the app reaches the final Local development sidebar model. A corrected registry row or HTTP 200 is not mount proof by itself. Open and render the route separately only when validating UI or runtime behavior.
|
|
524
|
+
- **`LOCAL_NOTIS_DATABASE_QUERY` returns empty documents**: Check that the database ID passed to the tool matches the intended database. Use `npx --package @notis_ai/cli@latest -- notis tools exec LOCAL_NOTIS_DATABASE_LIST_DATABASES --arguments '{}'` to verify the ID; use the database slug only as a fallback.
|
|
525
|
+
- **Properties are `undefined`**: Keep app-local result types for `useTool<TArgs, TResult>` and guard optional nested properties when reading live data.
|