@owlmeans/create-app 0.1.18-rc.4 → 0.1.18-rc.41

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 (78) hide show
  1. package/README.md +39 -2
  2. package/build/args.d.ts +8 -0
  3. package/build/args.d.ts.map +1 -1
  4. package/build/args.js +60 -6
  5. package/build/args.js.map +1 -1
  6. package/build/index.d.ts +4 -1
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +2 -0
  9. package/build/index.js.map +1 -1
  10. package/build/naming.d.ts +11 -0
  11. package/build/naming.d.ts.map +1 -0
  12. package/build/naming.js +18 -0
  13. package/build/naming.js.map +1 -0
  14. package/build/run.d.ts.map +1 -1
  15. package/build/run.js +19 -13
  16. package/build/run.js.map +1 -1
  17. package/build/scaffold.d.ts +21 -0
  18. package/build/scaffold.d.ts.map +1 -0
  19. package/build/scaffold.js +18 -0
  20. package/build/scaffold.js.map +1 -0
  21. package/build/template.d.ts +19 -3
  22. package/build/template.d.ts.map +1 -1
  23. package/build/template.js +52 -12
  24. package/build/template.js.map +1 -1
  25. package/package.json +4 -3
  26. package/template/AGENTS.md +28 -1
  27. package/template/README.bare.md +57 -0
  28. package/template/README.md +5 -61
  29. package/template/_agents/scripts/link-skills.sh +310 -15
  30. package/template/_agents/skills/agent-memory/SKILL.md +12 -11
  31. package/template/_agents/skills/getting-started/SKILL.md +26 -86
  32. package/template/_agents/skills/memory-promotion/SKILL.md +10 -4
  33. package/template/_agents/skills/memory-recompact/SKILL.md +15 -14
  34. package/template/_agents/skills/reuse-code/SKILL.md +36 -8
  35. package/template/_agents/skills/self-education/SKILL.md +25 -5
  36. package/template/_agents/skills/skill-authoring/SKILL.md +78 -12
  37. package/template/_bare.json +23 -0
  38. package/template/_gitignore +3 -0
  39. package/template/bunfig.toml +2 -0
  40. package/template/package.json +3 -2
  41. package/template/sources/api/package.json +3 -3
  42. package/template/sources/api/src/app/session/add.ts +7 -6
  43. package/template/sources/api/src/app/session/list.ts +12 -9
  44. package/template/sources/api/src/app/session/remove.ts +7 -6
  45. package/template/sources/api/src/context.bare.ts +11 -0
  46. package/template/sources/api/src/entrypoints.bare.ts +4 -0
  47. package/template/sources/api/src/entrypoints.ts +13 -0
  48. package/template/sources/api/src/index.ts +2 -2
  49. package/template/sources/api/src/types.bare.ts +5 -0
  50. package/template/sources/common/package.json +6 -6
  51. package/template/sources/common/src/consts.bare.ts +8 -0
  52. package/template/sources/common/src/consts.ts +0 -13
  53. package/template/sources/common/src/entrypoints.bare.ts +14 -0
  54. package/template/sources/common/src/entrypoints.ts +60 -0
  55. package/template/sources/common/src/index.bare.ts +3 -0
  56. package/template/sources/common/src/index.ts +1 -1
  57. package/template/sources/common/src/schemas.ts +7 -7
  58. package/template/sources/web/index.html +3 -1
  59. package/template/sources/web/package.json +13 -11
  60. package/template/sources/web/src/components/ui/dropdown-menu.tsx +257 -0
  61. package/template/sources/web/src/components/ui/navigation-menu.tsx +169 -0
  62. package/template/sources/web/src/context.bare.ts +13 -0
  63. package/template/sources/web/src/context.ts +14 -2
  64. package/template/sources/web/src/entrypoints.bare.ts +13 -0
  65. package/template/sources/web/src/entrypoints.ts +16 -0
  66. package/template/sources/web/src/index.css +7 -0
  67. package/template/sources/web/src/index.tsx +2 -2
  68. package/template/sources/web/src/layout/main.tsx +16 -19
  69. package/template/sources/web/src/nav.bare.ts +23 -0
  70. package/template/sources/web/src/nav.ts +30 -0
  71. package/template/sources/web/src/screens/about.tsx +19 -0
  72. package/template/sources/web/src/screens/home.bare.tsx +17 -0
  73. package/template/sources/web/src/screens/session.tsx +28 -14
  74. package/template/sources/web/src/vite-env.d.ts +1 -0
  75. package/template/sources/api/src/modules.ts +0 -11
  76. package/template/sources/common/src/modules.ts +0 -26
  77. package/template/sources/web/src/components/nav/main.tsx +0 -15
  78. package/template/sources/web/src/modules.ts +0 -20
@@ -1,105 +1,45 @@
1
1
  ---
2
2
  name: getting-started
3
- description: How to build a fullstack OwlMeans Common app from scratch — the common/api/web three-workspace pattern, context bootstrap on server and web, shared entrypoints + elevate(), and a session-scoped in-memory resource with @owlmeans/static-resource. Use when starting a new OwlMeans project, wiring web↔api, or asked how the pieces fit together.
4
- user-invocable: true
3
+ description: Start a protocol-first OwlMeans application with shared contracts, server entrypoints and browser entrypoints.
5
4
  metadata:
6
5
  scope: general
7
6
  ---
8
7
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
9
8
 
10
- # Getting started with OwlMeans Common — fullstack app shape
9
+ # Protocol-first application shape
11
10
 
12
- A minimal OwlMeans app is a **bun-workspace monorepo with three packages**:
13
-
14
- ```
15
- sources/
16
- ├── common/ # shared entrypoints (routes), AJV schemas, types, config — the single source of truth
17
- ├── api/ # @owlmeans/server-app backend; handlers attached to the shared entrypoints
18
- └── web/ # @owlmeans/web-panel + shadcn UI; screens attached to the same entrypoints
19
- ```
20
-
21
- The full, runnable walkthrough (scaffolded **and** manual) lives in
22
- [`docs/getting-started.md`](../../../docs/getting-started.md). To generate this exact project, use
23
- [[scaffolding]] (`npm create @owlmeans/app`). This skill is the mental model.
24
-
25
- ## The core idea: one contract, two sides
26
-
27
- Declare each route once in `common` as an **entrypoint**, then `elevate()` it on each side:
28
-
29
- ```ts
30
- // common/modules.ts — declaration + validation, no implementation
31
- export const sessionModules = [
32
- entrypoint(route(session.base, '/session')),
33
- entrypoint(route(session.list, '/:sid/items', { parent: session.base, method: RouteMethod.GET }),
34
- filter(params<SessionParams>(SessionParamsSchema))),
35
- entrypoint(route(session.add, '/:sid/items', { parent: session.base, method: RouteMethod.POST }),
36
- filter(params<SessionParams>(SessionParamsSchema, body<AddItemPayload>(AddItemSchema)))),
37
- ]
38
- ```
11
+ An OwlMeans application owns one shared protocol declaration and creates local entrypoints for each
12
+ runtime. The declaration is never modified by a server or browser.
39
13
 
40
14
  ```ts
41
- // api/modules.ts — attach handlers
42
- elevate(sessionModules, session.list, handlers.list)
43
- export const appModules = [...modules, ...sessionModules] // `modules` = framework defaults
15
+ // common/src/entrypoints.ts
16
+ export const sessionProtocols = {
17
+ list: protocol(
18
+ route(session.list, '/session', backend()),
19
+ contract.request({ query: typed<SessionQuery>(SessionQuerySchema) }, typed<Session[]>())
20
+ ),
21
+ }
44
22
  ```
45
23
 
46
24
  ```ts
47
- // web/modules.ts — attach screen components, plus call-only elevation for backend routes
48
- elevate(modules, session.list) // callable from the client
49
- modules.push(entrypoint(route(web.session, '/session', frontend({ parent: BASE })), handler(SessionScreen)))
50
- ```
51
-
52
- Change a route or schema in `common` and both sides stay in sync. See [[entrypoint]], [[route]],
53
- [[server-app]], [[web-client]], [[web-panel]].
54
-
55
- ## Shared config (where services live)
56
-
57
- `common/config.ts` registers both services so the web knows where the API is. `base: 'api'`
58
- prefixes API routes with `/api`:
59
-
60
- ```ts
61
- const cfg = service({ type: AppType.Frontend, service: APP_WEB, host: 'localhost', port: 3001 })
62
- service({ type: AppType.Backend, service: APP_API, host: 'localhost', port: 3000, base: 'api' }, cfg)
63
- cfg.debug = { all: true }
64
- export const commonConfig = cfg
25
+ // api/src/entrypoints.ts
26
+ const api = handlers<Context>()
27
+ export const serverBindings = [
28
+ ...frameworkEntrypoints,
29
+ bind(sessionProtocols.list, api.request(sessionProtocols.list, listSessions)),
30
+ ]
65
31
  ```
66
32
 
67
- api: `config(APP_API, commonConfig)` (+ `cfg.port`). web: `config(APP_WEB, commonConfig)`. See [[config]].
68
-
69
- ## Backend bootstrap + in-memory data
70
-
71
33
  ```ts
72
- // api/context.ts
73
- const context = makeContext(cfg, true) // from @owlmeans/server-app
74
- appendStaticResource(context, SESSION_ITEMS) // @owlmeans/static-resource — in-memory, no DB
75
- ```
76
-
77
- Handlers use `handleRequest` / `handleBody` / `handleParams` (validated payload, then context, then
78
- req). Read/write `ctx.getStaticResource<T>(alias)` — full CRUD (`get/load/list/create/save/delete`).
79
- **`static-resource.list()` takes no criteria** — list all and filter in JS (e.g. by `sessionId`).
80
- `main(context, appModules)` starts the server. See [[static-resource]], [[server-app]], [[resource]].
81
-
82
- Swap `@owlmeans/static-resource` for [[mongo-resource]] / [[redis-resource]] when you need
83
- persistence — the handler shape is identical.
84
-
85
- ## Web bootstrap (shadcn)
86
-
87
- `@owlmeans/web-panel`'s `PanelApp` is shadcn/Tailwind v4 (no MUI). The **app provides** the shadcn
88
- primitives at the `@` alias — `web-panel` references `@/lib/utils` and
89
- `@/components/ui/{alert,button,card,input,label,progress}`; copy those into `src/`. Render with
90
- `provide` from `@owlmeans/web-client`:
34
+ // web/src/entrypoints.ts
35
+ export const clientBindings = [
36
+ ...frameworkEntrypoints,
37
+ ...bindAll(sessionProtocols),
38
+ ]
91
39
 
92
- ```tsx
93
- basicRender(<PanelApp context={context} provide={provide} />)
40
+ const sessions = await context.entrypoint(sessionProtocols.list).call({ query: { sid } })
94
41
  ```
95
42
 
96
- `vite.config.ts` sets `@`→`src`, `@tailwindcss/vite`, and dedupes the owlmeans/react singletons.
97
- `index.css` is `@import "tailwindcss";` + a shadcn `@theme` token block (replaces `@owlmeans/owl-theme`).
98
- A parent `BASE` route renders the layout via `handler(LayoutComponent)`; `HOME` is its default child.
99
- Screens call the backend with `context.entrypoint(alias).call({ params, body })` → `[data, outcome]`.
100
- See [[web-panel]], [[web-client]], [[shadcn-web]], [[client-entrypoint]].
101
-
102
- ## Authentication
103
-
104
- This shape is intentionally **auth-free**. To add it: `@owlmeans/server-auth` + `@owlmeans/client-auth`
105
- and `guard(...)` on entrypoints. See [[auth-protocol]], [[server-auth]], [[client-auth]].
43
+ Use `schema<T>(...)` or `typed<T>(...)` at the contract boundary. Bind all route parents with their
44
+ children. Keep organization entity values on the wire as `entitySlug`; database relations use
45
+ `entityId` only.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: memory-promotion
3
- description: Transform procedure-shaped or repeatedly-used memory into skills and instructions — the procedure-shape test, the mandatory distillation rewrite, promote? repeated-touch flags, over-cap trigger, update-vs-create decision, and the post-promotion pointer state. Use when memory content reads as "how to", when a promote? flag is encountered again, when writing memory-derived content into a skill, or during recompaction.
3
+ description: Transform procedure-shaped or repeatedly-used memory into skills — the procedure-shape test, the mandatory distillation rewrite, promote? repeated-touch flags, over-cap trigger, update-vs-create decision, and the post-promotion pointer state. Use when memory content reads as "how to", when a promote? flag is encountered again, when writing memory-derived content into a skill, or during recompaction.
4
4
  user-invocable: true
5
5
  metadata:
6
6
  scope: general
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  # Memory promotion
11
11
 
12
- Memory holds **facts**; **procedures** belong in skills/instructions, where they auto-invoke and
12
+ Memory holds **facts**; **procedures** belong in skills, where they auto-invoke and
13
13
  stop consuming memory-read cycles. Promotion is how the store stays compact and the harness
14
14
  teaches itself.
15
15
 
@@ -79,8 +79,8 @@ Evaluable by reading the file alone — no tooling required.
79
79
 
80
80
  ## Update vs create
81
81
 
82
- **Default is update** — extend the existing skill/instruction whose scope covers the activity,
83
- even partially; keep both twins in sync. Create a NEW pair only when:
82
+ **Default is update** — extend the existing skill whose scope covers the activity, even
83
+ partially. Create a NEW skill only when:
84
84
 
85
85
  - (a) a new subsystem or technology entered the repo;
86
86
  - (b) an activity with no covering skill needed memory read/write more than once (a
@@ -90,6 +90,12 @@ even partially; keep both twins in sync. Create a NEW pair only when:
90
90
  New skills multiply lookup cost — compactness applies to the skill population *and* to each
91
91
  skill's body.
92
92
 
93
+ The covering skill may be one this project does not own — a `.agents/linked-skills/<name>` entry
94
+ symlinked into an upstream repo or installed package, or an installer-placed copy carrying the
95
+ `AUTO-GENERATED` banner. Never write the promotion into either: put the distilled rule in a local
96
+ skill and name it after the activity, because a local skill named after the upstream one shadows
97
+ that skill for the whole project (`self-education` → Skills this project does not own).
98
+
93
99
  ## Procedure
94
100
 
95
101
  1. Collect the flagged / procedure-shaped memory lines.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: memory-recompact
3
- description: Recompact or migrate a whole .agents/memory/ store — rebuild the node map from project structure, merge event-shaped records into subsystem nodes, deduplicate, enforce caps, regenerate the MEMORY.md index, and fold in legacy .claude/memory and .github/memory stores. Use when a store degrades into event logs, indexes bloat or conflict, or for one-time migration.
3
+ description: Recompact a whole .agents/memory/ store — rebuild the node map from project structure, merge event-shaped records into subsystem nodes, deduplicate, enforce caps, regenerate the MEMORY.md index, and fold in memory records kept anywhere else. Use when a store degrades into event logs, when indexes bloat or conflict, or when scattered records have to become one store.
4
4
  disable-model-invocation: true
5
5
  metadata:
6
6
  scope: general
@@ -9,9 +9,9 @@ metadata:
9
9
 
10
10
  # Memory recompaction
11
11
 
12
- Whole-store maintenance for `.agents/memory/` (protocol: `agent-memory`). Also the migration
13
- procedure for legacy `.claude/memory/` + `.github/memory/` stores. Store-wide rewrite — propose
14
- it when triggers appear; the operator invokes it.
12
+ Whole-store maintenance for `.agents/memory/` (protocol: `agent-memory`), and the procedure for
13
+ folding records kept anywhere else into it. Store-wide rewrite — propose it when triggers appear;
14
+ the operator invokes it.
15
15
 
16
16
  ## When
17
17
 
@@ -20,7 +20,8 @@ it when triggers appear; the operator invokes it.
20
20
  - The same fact stated in two or more nodes.
21
21
  - More than ~20% of a node is stale `Status` content.
22
22
  - A node's `updated:` is months behind commits touching its scope.
23
- - Legacy `.claude/memory/` or `.github/memory/` dirs exist → run the migration below.
23
+ - Memory records live outside `.agents/memory/` — a second store, a per-agent directory, a stray
24
+ notes file → fold them in with the merge pass below.
24
25
 
25
26
  ## Build the target node map first
26
27
 
@@ -43,14 +44,14 @@ For each old file or section:
43
44
  4. Procedure-shaped survivors do not enter nodes — route them to `memory-promotion`. Routing
44
45
  means distilling them into general rules, never handing the text over verbatim.
45
46
 
46
- ## Legacy-store merge (migration)
47
+ ## Folding in an outside store
47
48
 
48
- 1. Union `.claude/memory/` and `.github/memory/`. Same-named files are two drifted sources of
49
- ONE node — merge both; the code-consistent version wins.
49
+ 1. Union every source. Two same-named files are two drifted sources of ONE node — merge both;
50
+ the code-consistent version wins.
50
51
  2. Index-only entries with no backing file: extract the fact into its node, or drop if stale.
51
- 3. Old `## Skills` / "Key Files" index sections are dropped — skills self-describe; harness
52
- layout belongs to `AGENTS.md`. Move genuinely non-obvious dispatch hints there.
53
- 4. When the new store verifies (below), delete both legacy dirs entirely.
52
+ 3. `## Skills` / "Key Files" index sections are dropped — skills self-describe; harness layout belongs to `AGENTS.md`; a genuinely non-obvious dispatch hint goes into the
53
+ owning skill's `description:`, never into `AGENTS.md`.
54
+ 4. When the new store verifies (below), delete every merged source entirely.
54
55
 
55
56
  ## Regenerate the index
56
57
 
@@ -62,9 +63,9 @@ index incrementally.
62
63
  - Every node file is listed in the index; every listed node exists; every wiki-link resolves.
63
64
  - All caps met (index ≤ 50 lines; nodes ≤ 120; entries ≤ 3 lines; Status ≤ 5 dated lines).
64
65
  - No dates outside `Status` and `updated:`; no event-keyed filenames.
65
- - Both root instruction files' Memory sections point at `.agents/memory/`.
66
- - Legacy dirs gone; `grep -rn '\.claude/memory\|\.github/memory'` over the repo's harness files
67
- returns nothing but allowlisted historical mentions.
66
+ - The root `AGENTS.md` Memory section points at `.agents/memory/`.
67
+ - `.agents/memory/` is the only memory store left: every merged source directory or file is
68
+ deleted, and nothing in the harness still points at one.
68
69
 
69
70
  ## Report
70
71
 
@@ -18,9 +18,17 @@ order — during planning **and** during implementation.
18
18
  Before suggesting any external library or writing custom code, look for an `@owlmeans/*` package that
19
19
  already solves the problem.
20
20
 
21
- - **Consult the deployed skills.** Each installed `@owlmeans/*` package ships a skill at
22
- `.agents/skills/<pkg>/SKILL.md` describing what it
23
- does. Read those first — they are your local catalogue of installed capabilities.
21
+ - **Consult the deployed skills.** `.agents/skills/` is the local catalogue of installed
22
+ capabilities: one directory per skill, each holding a `SKILL.md` that describes what a package
23
+ does and how it is consumed. A directory is named after the **skill**, not the package —
24
+ `@owlmeans/test-ui` deploys `testing-ui`, `@owlmeans/server-auth` deploys `server-auth` **and**
25
+ `supervisor-auth`, `@owlmeans/test` deploys `testing-unit` and `testing-overview` — so list the
26
+ directory instead of guessing a path from a package name.
27
+ - **Read `.agents/linked-skills/` too when it is there.** `.agents/scripts/link-skills.sh` links
28
+ the skills that ship inside the installed `@owlmeans/*` packages into it (and mirrors them into
29
+ `.claude/skills/` for Claude Code), with a skill / origin / description table in its
30
+ `INDEX.md`. It is generated and git-ignored, and a skill of the same name in `.agents/skills/`
31
+ always wins.
24
32
  - **Scan installed packages.** Look in `node_modules/@owlmeans/*` **and**, in a workspace monorepo,
25
33
  the nested `sources/*/node_modules/@owlmeans/*` (bun nests workspace deps).
26
34
  - **Discover packages that aren't installed yet** by researching the **owlmeans/common** repository —
@@ -39,13 +47,31 @@ How you research the repo depends on whether `@owlmeans/*` is linked locally:
39
47
  **https://github.com/owlmeans/common** — `tree.md` and package READMEs — to find the right package.
40
48
 
41
49
  This is the same dev-linked detection `@owlmeans/agent-skills` uses (see its `detectLinked`). After
42
- adding an `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills` to deploy its skill. Prefer an
43
- `@owlmeans/*` package over a third-party library or bespoke code whenever one fits.
50
+ adding an `@owlmeans/*` dependency, run `npx @owlmeans/agent-skills@^0.1.18-rc.32` to deploy its
51
+ skill. Prefer an `@owlmeans/*` package over a third-party library or bespoke code whenever one fits.
52
+
53
+ ### Never add an OwlMeans dependency without an explicit range
54
+
55
+ Write the range yourself, as a caret at the version the rest of this project already uses for its
56
+ other `@owlmeans/*` packages:
57
+
58
+ ```json
59
+ "dependencies": {
60
+ "@owlmeans/queue": "^0.1.18-rc.27"
61
+ }
62
+ ```
63
+
64
+ A `bun add` that names no version — and a hand-written `"latest"`, `"next"`, `"*"` or empty range
65
+ — resolves through a dist-tag instead. OwlMeans publishes prereleases under `next`, so the tag
66
+ named `latest` points at an OLDER version than the one every other package here is pinned to. The
67
+ install succeeds, nothing warns, and the code you wrote against the current API is compiled
68
+ against the previous one. Put the version in the same breath as the package name, or copy the
69
+ `**Install:**` line from that package's own skill, which always carries a current range.
44
70
 
45
71
  ## 2. Reuse or extend before writing custom
46
72
 
47
73
  If an installed package nearly fits, **configure or extend it** rather than writing something new — use
48
- its resources, services, modules, and helpers. A small extension of a framework package beats a new
74
+ its resources, services, entrypoints, and helpers. A small extension of a framework package beats a new
49
75
  parallel implementation.
50
76
 
51
77
  ## 3. No package? Reuse code and extract an abstraction
@@ -60,5 +86,7 @@ Once code is written, review it: can it be **shorter, clearer, or expressed with
60
86
  Lean on framework utilities, remove dead branches, collapse needless indirection. Less code that reuses
61
87
  the framework is better than more bespoke code.
62
88
 
63
- See `[[dependency-tree]]` for the package map, `[[scaffolding]]` for how a project is assembled, and
64
- `[[bun]]` for adding dependencies.
89
+ See `[[scaffolding]]` for how a project is assembled, and `[[agent-skills]]` for keeping the
90
+ deployed skill catalogue current. The package map itself is `tree.md` at the root of the
91
+ [owlmeans/common](https://github.com/owlmeans/common) repository — layer by layer, every package
92
+ and what it depends on.
@@ -27,10 +27,14 @@ Also recommended after any unplanned change that made an existing skill inaccura
27
27
 
28
28
  For each area the work touched:
29
29
 
30
- 1. Which existing skill covers it? (Check `.agents/skills/`.)
30
+ 1. Which existing skill covers it? Check `.agents/skills/`, and — where the project has one —
31
+ `.agents/linked-skills/`, for ground a skill this project does not own already covers.
31
32
  2. Do its commands, paths, APIs, and behavior claims still hold after the change?
32
33
  3. Fix in place — rewrite the affected lines so they describe current behavior; never append a
33
34
  note about what this change did.
35
+ 4. Never record what the work taught in `AGENTS.md`: the rule goes to the governing skill, the
36
+ incident to `.agents/memory/`. `AGENTS.md` gains at most a new skill's one index line or a new
37
+ repo-wide mandatory rule in one line (`create-skill` → What may enter AGENTS.md).
34
38
 
35
39
  ## Shape of an update
36
40
 
@@ -46,11 +50,24 @@ rewrite recipe is `memory-promotion` → Distillation.
46
50
 
47
51
  Test: a finished skill reads as though the feature was always this way.
48
52
 
49
- ## Non-project skills
53
+ ## Skills this project does not own
50
54
 
51
- If a general or imported skill gained an important usage pattern during the work, add the pattern
52
- to the **deployed copy** in this repo and note it in the report as an upstream candidate —
53
- canonical archive copies change only on explicit operator request.
55
+ A skill that came from somewhere else is not edited here, and the two kinds fail differently:
56
+
57
+ - An entry under `.agents/linked-skills/<name>` is a symlink into the repo or installed package
58
+ that owns the skill. Writing through it edits the owner's own file — an unrequested change in
59
+ another project, which nothing here undoes: the link script only creates and prunes symlinks.
60
+ - A skill placed by the `@owlmeans/agent-skills` installer is a real file at
61
+ `.agents/skills/<name>/SKILL.md` carrying
62
+ `<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->`. The next install
63
+ overwrites every file still carrying that banner, so an edit made under it is lost; strip the
64
+ banner and the file instead becomes a conflict the installer skips and reports.
65
+
66
+ When such a skill gained an important usage pattern during the work, capture the pattern in a
67
+ local skill under `.agents/skills/`, named after the pattern — a local skill named after the
68
+ upstream one shadows it for the whole project — and list the upstream skill in the report as an
69
+ upstream candidate. Changing the skill at its source is a separate change in the owning project,
70
+ made only on explicit operator request.
54
71
 
55
72
  ## External docs
56
73
 
@@ -73,6 +90,9 @@ memory-vs-skill boundary (`agent-memory` / `memory-promotion`).
73
90
 
74
91
  ## Completion gate
75
92
 
93
+ Before reporting, run `sh .agents/scripts/agents-size.sh`; if `AGENTS.md` is over budget, move
94
+ lines out to their skills first.
95
+
76
96
  The completion report must contain a Self-education table:
77
97
 
78
98
  | Item | Action | Path |
@@ -9,13 +9,26 @@ metadata:
9
9
 
10
10
  # Authoring agent guidance (skills)
11
11
 
12
- OwlMeans projects carry agent guidance in two places, and only two:
12
+ An OwlMeans project carries agent guidance in up to three places:
13
13
 
14
14
  | What | Where | Loaded |
15
15
  |---|---|---|
16
16
  | Always-on project context | `AGENTS.md` at the repo root | every session |
17
+ | Always-on policy, kept out of `AGENTS.md` | `.agents/rules/<topic>.md`, pulled in from `AGENTS.md` by an `@.agents/rules/<topic>.md` import line | every session |
17
18
  | Topic guidance | `.agents/skills/<name>/SKILL.md` | on demand, by topic or `/<name>` |
18
19
 
20
+ The middle tier is optional and belongs to a repo that has grown standing policy of its own. A
21
+ project scaffolded by `@owlmeans/create-app` starts without a `.agents/rules/` directory: its
22
+ generated `AGENTS.md` states the git policy inline and points at the seeded `git` skill for the
23
+ rest. Follow the layout the project already has — add a rules file only where `AGENTS.md` already
24
+ imports one.
25
+
26
+ **Rule or skill?** A rule is policy that has to hold whether or not anyone thought to load
27
+ anything — the git workflow is the standing example, whether a repo keeps it as
28
+ `.agents/rules/git.md` or inline in `AGENTS.md`. A skill is guidance for a task, loaded when that
29
+ task comes up. If it only matters while you are doing X, write a skill; if breaking it is wrong at any moment, state it in a line or two where `AGENTS.md` loads it every
30
+ session, and keep its detail in a skill (§ What may enter AGENTS.md).
31
+
19
32
  `.agents/skills/` is the [Agent Skills](https://agentskills.io) standard location: GitHub Copilot
20
33
  and Codex discover it natively. Claude Code reads skills only from `.claude/skills/`, so each skill
21
34
  is bridged there by a generated symlink — see "Refresh the Claude Code links" below. **Write a skill
@@ -38,20 +51,43 @@ once; never author a per-agent copy** (`.github/instructions/*.instructions.md`,
38
51
  name: my-skill # REQUIRED, must equal the directory name (lowercase, hyphens, ≤64 chars)
39
52
  description: What it does and WHEN to use it. # REQUIRED, ≤1024 chars — the auto-invocation signal
40
53
  user-invocable: true # false = background knowledge only, hidden from the / menu
41
- allowed-tools: Bash(bun *) Read # optional — space-separated; tools usable without per-call approval
54
+ allowed-tools: Bash(bun *), Read # optional — COMMA-separated; tools usable without per-call approval
42
55
  metadata: # optional — anything non-standard goes here
43
56
  scope: general
44
57
  ---
45
58
  ```
46
59
 
60
+ The `name` is not free: it is the key every store is keyed by, and a LOCAL skill always wins over
61
+ one that arrives from a dependency. Naming a skill after a package you depend on therefore hides
62
+ that package's own guidance completely, and the installer reports the file as a conflict on every
63
+ run. Give a skill about your own use of `@owlmeans/payment` a name of its own — `billing`, or your
64
+ product's name with a suffix — never `payment`.
65
+
66
+ **Never name a skill after a Claude Code built-in slash command.** Claude Code resolves `/<name>` to
67
+ a skill before the built-in command of the same name, so a skill called `context`, `config`,
68
+ `memory` or `review` makes that command unreachable wherever the skill is installed or linked, and
69
+ nothing reports it. The same holds for a command's aliases (`/settings` is `/config`, `/cost` is
70
+ `/usage`) and for the skills Claude Code bundles (`/loop`, `/simplify`); type `/` in a Claude Code
71
+ session to see every taken name. OwlMeans package skills follow this too: the guidance for
72
+ `@owlmeans/context` and `@owlmeans/config` ships as `owlmeans-context` and `owlmeans-config`.
73
+
47
74
  The `description` is the most important field: every agent uses it to decide when to load the
48
75
  skill, so state both the topic and the trigger ("Use when …"). Keep it under 1024 characters —
49
- Copilot rejects longer ones.
50
-
51
- Only the fields above (plus `license` and `compatibility`) are portable. Anything else — including
52
- this monorepo's `scope: general` routing marker — belongs under `metadata:`, so a skill stays valid
53
- in every agent that reads it. Claude Code additionally understands `disable-model-invocation`,
54
- `argument-hint` and `context: fork`; use them only when the skill genuinely needs them.
76
+ Copilot rejects longer ones. It is YAML, so a value containing `: ` (colon-space) has to be quoted
77
+ or the file stops parsing and the skill silently disappears from every agent.
78
+
79
+ `allowed-tools` is parsed as a list split on commas, newlines and YAML `-` bullets — never on
80
+ plain spaces. `Bash(bun *) Read` is read as one tool named `Bash(bun *) Read`, which matches
81
+ nothing; write `Bash(bun *), Read`.
82
+
83
+ Six keys are what the Agent Skills frontmatter parser in `@owlmeans/agent-skills` stores:
84
+ `name`, `description`, `license`, `compatibility`, `allowed-tools` and nested `metadata`.
85
+ Project-specific keys — including the OwlMeans `scope: general` routing marker, which sends a skill
86
+ to the installer bundle rather than to one package — belong under `metadata:`, so a skill stays
87
+ valid in every agent that reads it. The invocation switches sit outside what that parser stores and
88
+ are written at the top level alongside it: `user-invocable` (`false` hides a skill from the `/`
89
+ menu, marking it background knowledge), plus `disable-model-invocation` and `argument-hint`, which
90
+ Claude Code understands. Set any of them only when the skill needs it.
55
91
 
56
92
  ## Refresh the Claude Code links
57
93
 
@@ -61,9 +97,23 @@ After creating, renaming, or deleting a skill, run:
61
97
  sh .agents/scripts/link-skills.sh
62
98
  ```
63
99
 
64
- It creates `.claude/skills/<name>` → `../../.agents/skills/<name>` for every skill and prunes links
65
- whose skill is gone. The links are gitignored and are recreated at session start, but a skill added
66
- mid-session is invisible to Claude Code until the script runs.
100
+ It creates `.claude/skills/<name>` → `../../.agents/skills/<name>` for every local skill and prunes
101
+ links whose skill is gone. The links are gitignored and are recreated at session start (a committed
102
+ `SessionStart` hook, and on every install where the project declares a root `prepare` script that
103
+ calls it), but a skill added mid-session is invisible to Claude Code until the script runs.
104
+
105
+ The same script also brings in the skills of everything this project depends on, from whichever of
106
+ two sources applies. In a linked checkout — a repo whose root `package.json` lists an upstream
107
+ repo's packages as workspace entries — it resolves those upstream repos first, recursing into each
108
+ one's own manifest up to four levels, and links the skills from the upstream's own
109
+ `.agents/skills/`. A project that declares no such linked upstream falls back to what a plain npm
110
+ install gives it: the read-only `agent-meta/skills/` copies shipped inside each installed
111
+ `@owlmeans/*` package. Either way the links land in `.agents/linked-skills/<name>` (Copilot, Codex)
112
+ and `.claude/skills/<name>` (Claude Code), with a generated `.agents/linked-skills/INDEX.md` listing
113
+ skill, origin and description. Load one by name exactly like a local skill. A local skill of the
114
+ same name always wins, and a nearer dependency wins over a farther one. The whole
115
+ `.agents/linked-skills/` directory is generated and git-ignored — never edit or commit it, and never
116
+ edit an `agent-meta/` copy: fix the skill in the package that ships it.
67
117
 
68
118
  ## Skill vs memory
69
119
 
@@ -80,10 +130,26 @@ Never paste memory text into a skill. Memory content enters guidance only as a r
80
130
  rule — trigger, step, and the failure it prevents, with dates, phase/status markers, versions and
81
131
  incident narrative stripped (`memory-promotion` → Distillation).
82
132
 
133
+ ## What may enter AGENTS.md
134
+
135
+ `AGENTS.md` — with every file it `@`-imports and `.agents/memory/MEMORY.md` — is loaded in full in
136
+ every session, so it has a budget: **≤ 40 000 chars**, checked by `sh .agents/scripts/agents-size.sh`
137
+ from the repo root where the repo carries it. A line enters it only as:
138
+
139
+ 1. a mandatory rule that must hold before any skill is loaded (git, reporting, environments,
140
+ naming) — stated in one or two lines, with the detail in a skill;
141
+ 2. one line of the package map or the command list;
142
+ 3. one line of the skills index: `` - `/name` — when to load it ``, ≤ 160 chars.
143
+
144
+ Everything else is loaded on demand: a subsystem's rules, contracts and failure fingerprints go to
145
+ the skill that governs it, and the outage that taught them to `.agents/memory/`. Never paraphrase a
146
+ skill's `description:` into the index — skills self-describe. A change that would push the file over
147
+ budget shortens or moves an existing line in the same change.
148
+
83
149
  ## After adding a skill
84
150
 
85
151
  1. If it replaces an ad-hoc `.agents/<topic>.md`, remove that file.
86
152
  2. If it distilled memory content into rules, shrink the source `.agents/memory/` node to a
87
153
  pointer line (`memory-promotion`) — the memory index does not list skills.
88
- 3. Reference it from `AGENTS.md` if it should be discoverable every session.
154
+ 3. Add one line to the skills index in `AGENTS.md` (`/name` — when to load it, ≤ 160 chars) — never a paragraph (§ What may enter AGENTS.md).
89
155
  4. Run `sh .agents/scripts/link-skills.sh`.
@@ -0,0 +1,23 @@
1
+ {
2
+ "remove": [
3
+ "sources/common/src/types.ts",
4
+ "sources/common/src/schemas.ts",
5
+ "sources/api/src/consts.ts",
6
+ "sources/api/src/app",
7
+ "sources/web/src/screens/about.tsx",
8
+ "sources/web/src/screens/session.tsx"
9
+ ],
10
+ "overrides": {
11
+ "README.md": "README.bare.md",
12
+ "sources/common/src/consts.ts": "sources/common/src/consts.bare.ts",
13
+ "sources/common/src/entrypoints.ts": "sources/common/src/entrypoints.bare.ts",
14
+ "sources/common/src/index.ts": "sources/common/src/index.bare.ts",
15
+ "sources/api/src/context.ts": "sources/api/src/context.bare.ts",
16
+ "sources/api/src/entrypoints.ts": "sources/api/src/entrypoints.bare.ts",
17
+ "sources/api/src/types.ts": "sources/api/src/types.bare.ts",
18
+ "sources/web/src/context.ts": "sources/web/src/context.bare.ts",
19
+ "sources/web/src/entrypoints.ts": "sources/web/src/entrypoints.bare.ts",
20
+ "sources/web/src/nav.ts": "sources/web/src/nav.bare.ts",
21
+ "sources/web/src/screens/home.tsx": "sources/web/src/screens/home.bare.tsx"
22
+ }
23
+ }
@@ -9,3 +9,6 @@ bun.lockb
9
9
  # Generated Claude Code skill symlinks (canonical skills live in .agents/skills/)
10
10
  .claude/skills/*
11
11
  !.claude/skills/.gitkeep
12
+
13
+ # Skills linked from upstream repos (generated by .agents/scripts/link-skills.sh)
14
+ .agents/linked-skills/
@@ -0,0 +1,2 @@
1
+ [install]
2
+ linker = "hoisted"
@@ -3,14 +3,15 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
- "packageManager": "bun@1.3.14",
6
+ "packageManager": "bun@1.4.0",
7
7
  "workspaces": [
8
8
  "sources/*"
9
9
  ],
10
10
  "scripts": {
11
11
  "dev": "bun run --filter './sources/common' build && bun run --filter './sources/*' --parallel dev",
12
12
  "build": "bun run --filter './sources/*' build",
13
- "typecheck": "bun run --filter './sources/*' typecheck"
13
+ "typecheck": "bun run --filter './sources/*' typecheck",
14
+ "prepare": "sh -c 'test -f .agents/scripts/link-skills.sh && sh .agents/scripts/link-skills.sh || true'"
14
15
  },
15
16
  "devDependencies": {
16
17
  "nodemon": "^3.1.14"
@@ -11,12 +11,12 @@
11
11
  "typecheck": "tsc -b"
12
12
  },
13
13
  "dependencies": {
14
- "@owlmeans/server-app": "^0.1.16",
15
- "@owlmeans/static-resource": "^0.1.16",
14
+ "@owlmeans/server-app": "^0.1.18-rc.37",
15
+ "@owlmeans/static-resource": "^0.1.18-rc.29",
16
16
  "__APP_SLUG__-common": "workspace:^"
17
17
  },
18
18
  "devDependencies": {
19
- "@owlmeans/dep-config": "^0.1.16",
19
+ "@owlmeans/dep-config": "^0.1.18-rc.6",
20
20
  "@types/node": "^24.10.1",
21
21
  "typescript": "^7.0.2"
22
22
  }
@@ -1,13 +1,14 @@
1
1
  import { randomUUID } from 'node:crypto'
2
- import { handleBody } from '@owlmeans/server-app'
3
- import type { AddItemPayload, SessionItem, SessionParams } from '__APP_SLUG__-common'
2
+ import { handlers } from '@owlmeans/server-app'
3
+ import { session, type SessionItem } from '__APP_SLUG__-common'
4
4
  import { SESSION_ITEMS } from '../../consts.js'
5
5
  import type { Context } from '../../types.js'
6
6
 
7
- export const add = handleBody<AddItemPayload>(async (payload, context, req) => {
8
- const ctx = context as Context
9
- const { sid } = req.params as SessionParams
10
- const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
7
+ const handle = handlers<Context>()
8
+
9
+ export const add = handle.body(session.add, async (payload, context, request) => {
10
+ const { sid } = request.params
11
+ const resource = context.getStaticResource<SessionItem>(SESSION_ITEMS)
11
12
 
12
13
  const item: SessionItem = {
13
14
  id: randomUUID(),
@@ -1,15 +1,18 @@
1
- import { handleParams } from '@owlmeans/server-app'
2
- import type { SessionItem, SessionParams } from '__APP_SLUG__-common'
1
+ import { handlers } from '@owlmeans/server-app'
2
+ import { session, type SessionItem } from '__APP_SLUG__-common'
3
3
  import { SESSION_ITEMS } from '../../consts.js'
4
4
  import type { Context } from '../../types.js'
5
5
 
6
- export const list = handleParams<SessionParams>(async (params, context) => {
7
- const ctx = context as Context
8
- const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
6
+ const handle = handlers<Context>()
7
+
8
+ export const list = handle.params(session.list, async (params, context) => {
9
+ const resource = context.getStaticResource<SessionItem>(SESSION_ITEMS)
10
+
11
+ // The resource answers the whole question — this session's items, newest first.
12
+ const { items } = await resource.list(
13
+ { sessionId: params.sid },
14
+ { sort: [{ field: 'createdAt', order: 'desc' }] }
15
+ )
9
16
 
10
- // The static resource lists every record; filter to this session and sort newest first.
11
- const { items } = await resource.list<SessionItem>()
12
17
  return items
13
- .filter(item => item.sessionId === params.sid)
14
- .sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1))
15
18
  })