@owlmeans/create-app 0.1.18-rc.7 → 0.1.18
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 +49 -5
- package/THIRD-PARTY-NOTICES.txt +24 -0
- package/build/args/types.d.ts +9 -0
- package/build/args/types.d.ts.map +1 -0
- package/build/args/types.js +2 -0
- package/build/args/types.js.map +1 -0
- package/build/args.d.ts +3 -20
- package/build/args.d.ts.map +1 -1
- package/build/args.js +121 -88
- package/build/args.js.map +1 -1
- package/build/bin.js +3 -3
- package/build/bin.js.map +1 -1
- package/build/consts.d.ts +6 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +6 -0
- package/build/consts.js.map +1 -0
- package/build/consts.local.d.ts +12 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +49 -0
- package/build/consts.local.js.map +1 -0
- package/build/index.d.ts +11 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -2
- package/build/index.js.map +1 -1
- package/build/naming/types.d.ts +14 -0
- package/build/naming/types.d.ts.map +1 -0
- package/build/naming/types.js +2 -0
- package/build/naming/types.js.map +1 -0
- package/build/naming.d.ts +4 -0
- package/build/naming.d.ts.map +1 -0
- package/build/naming.js +18 -0
- package/build/naming.js.map +1 -0
- package/build/run.d.ts +1 -1
- package/build/run.d.ts.map +1 -1
- package/build/run.js +23 -17
- package/build/run.js.map +1 -1
- package/build/scaffold.d.ts +8 -0
- package/build/scaffold.d.ts.map +1 -0
- package/build/scaffold.js +19 -0
- package/build/scaffold.js.map +1 -0
- package/build/template/types.d.ts +16 -0
- package/build/template/types.d.ts.map +1 -0
- package/build/template/types.js +2 -0
- package/build/template/types.js.map +1 -0
- package/build/template.d.ts +3 -16
- package/build/template.d.ts.map +1 -1
- package/build/template.js +69 -52
- package/build/template.js.map +1 -1
- package/build/types.d.ts +61 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +8 -6
- package/template/AGENTS.md +61 -2
- package/template/README.bare.md +70 -0
- package/template/README.md +9 -60
- package/template/_agents/scripts/link-skills.sh +327 -15
- package/template/_agents/skills/agent-memory/SKILL.md +12 -11
- package/template/_agents/skills/getting-started/SKILL.md +38 -79
- package/template/_agents/skills/logging/SKILL.md +41 -0
- package/template/_agents/skills/memory-promotion/SKILL.md +10 -4
- package/template/_agents/skills/memory-recompact/SKILL.md +15 -14
- package/template/_agents/skills/owlmeans-code-structure/SKILL.md +188 -0
- package/template/_agents/skills/owlmeans-code-structure/parts/code-structure-reference.md +125 -0
- package/template/_agents/skills/reuse-code/SKILL.md +56 -10
- package/template/_agents/skills/self-education/SKILL.md +25 -5
- package/template/_agents/skills/skill-authoring/SKILL.md +132 -14
- package/template/_bare.json +24 -0
- package/template/_gitignore +8 -0
- package/template/bunfig.toml +2 -0
- package/template/package.json +3 -2
- package/template/sources/api/package.json +5 -4
- package/template/sources/api/src/app/session/add.ts +6 -17
- package/template/sources/api/src/app/session/list.ts +6 -12
- package/template/sources/api/src/app/session/remove.ts +6 -15
- package/template/sources/api/src/config.ts +7 -0
- package/template/sources/api/src/context.bare.ts +11 -0
- package/template/sources/api/src/context.ts +0 -4
- package/template/sources/api/src/entrypoints.bare.ts +4 -0
- package/template/sources/api/src/entrypoints.ts +13 -0
- package/template/sources/api/src/index.ts +8 -2
- package/template/sources/api/src/models/session/types.ts +14 -0
- package/template/sources/api/src/models/session.ts +43 -0
- package/template/sources/api/src/types.bare.ts +5 -0
- package/template/sources/common/package.json +8 -8
- package/template/sources/common/src/config.ts +2 -1
- package/template/sources/common/src/consts.bare.ts +8 -0
- package/template/sources/common/src/consts.ts +0 -13
- package/template/sources/common/src/entrypoints.bare.ts +14 -0
- package/template/sources/common/src/entrypoints.ts +60 -0
- package/template/sources/common/src/index.bare.ts +3 -0
- package/template/sources/common/src/index.ts +1 -1
- package/template/sources/common/src/schemas.ts +7 -7
- package/template/sources/web/THIRD-PARTY-NOTICES.txt +24 -0
- package/template/sources/web/index.html +3 -1
- package/template/sources/web/package.json +33 -31
- package/template/sources/web/src/components/ui/dropdown-menu.tsx +257 -0
- package/template/sources/web/src/components/ui/navigation-menu.tsx +169 -0
- package/template/sources/web/src/config.ts +8 -0
- package/template/sources/web/src/consts.ts +15 -0
- package/template/sources/web/src/context.bare.ts +13 -0
- package/template/sources/web/src/context.ts +1 -7
- package/template/sources/web/src/entrypoints.bare.ts +13 -0
- package/template/sources/web/src/entrypoints.ts +16 -0
- package/template/sources/web/src/index.css +7 -0
- package/template/sources/web/src/index.tsx +2 -2
- package/template/sources/web/src/layout/main.tsx +17 -19
- package/template/sources/web/src/nav.bare.ts +24 -0
- package/template/sources/web/src/nav.ts +23 -0
- package/template/sources/web/src/screens/about.tsx +19 -0
- package/template/sources/web/src/screens/home.bare.tsx +17 -0
- package/template/sources/web/src/screens/session.tsx +14 -16
- package/template/sources/web/src/vite-env.d.ts +8 -0
- package/template/sources/web/vite.config.ts +4 -2
- package/template/CLAUDE.md +0 -13
- package/template/sources/api/src/modules.ts +0 -11
- package/template/sources/common/src/modules.ts +0 -26
- package/template/sources/web/src/components/nav/main.tsx +0 -15
- package/template/sources/web/src/modules.ts +0 -20
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reuse-code
|
|
3
|
-
description: Discovery-first, reuse-first workflow for OwlMeans projects. Use BEFORE planning or building any feature, before proposing a third-party library or a custom solution, and after writing code. Find an existing @owlmeans/* package or existing code first; extend before writing new; simplify what you write.
|
|
3
|
+
description: Discovery-first, reuse-first workflow for OwlMeans projects. Use BEFORE planning or building any feature, before proposing a third-party library or a custom solution, and after writing code. Find an existing @owlmeans/* package or existing code first (membership, invitations, organizations and access come from the IAM); extend before writing new; simplify what you write.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata:
|
|
6
6
|
scope: general
|
|
@@ -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.**
|
|
22
|
-
|
|
23
|
-
does.
|
|
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,20 +47,56 @@ 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
|
|
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` 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 (or the one the package's own skill names on its **Install:** line):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@owlmeans/queue": "^<version>"
|
|
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,
|
|
74
|
+
its resources, services, entrypoints, and helpers. A small extension of a framework package beats a new
|
|
49
75
|
parallel implementation.
|
|
50
76
|
|
|
77
|
+
### People, organizations and access come from the IAM
|
|
78
|
+
|
|
79
|
+
An application that signs its people in through an OwlMeans IAM provider already has accounts,
|
|
80
|
+
organizations, memberships, invitations and grants — the provider keeps them. Before writing a
|
|
81
|
+
members table, an invitation flow, a role column or an organization picker:
|
|
82
|
+
|
|
83
|
+
- **Server** (`@owlmeans/server-iam`): `makeIamRuntimeClient(context, request)` lists the person's
|
|
84
|
+
organizations, creates one, lists / adds (find-or-create by e-mail) / updates / removes members,
|
|
85
|
+
and lists, assigns and revokes grants — as the signed-in person, with owner and member rights
|
|
86
|
+
decided by the provider. `makeOrganizationScope(context, request).organizationOf` /
|
|
87
|
+
`.organizationsOf` read the session's organizations; gates and `hasPermission` enforce access;
|
|
88
|
+
`makeEntityScope(req).requireEntityKey()` is the tenant key to store records by.
|
|
89
|
+
- **Browser** (`@owlmeans/client-iam`): `organizationSwitchOf(ctx).listOrganizations` /
|
|
90
|
+
`.switchOrganization` — the acting organization is session state, never a per-request parameter.
|
|
91
|
+
- If the project's own scaffold already ships an organization switcher or a people / access screen,
|
|
92
|
+
extend it rather than adding a second one.
|
|
93
|
+
|
|
51
94
|
## 3. No package? Reuse code and extract an abstraction
|
|
52
95
|
|
|
53
96
|
When no package solves it, search the codebase for code that already solves a **similar** problem.
|
|
54
97
|
Prefer factoring out a shared helper, base, or generic function — extract an abstraction — over
|
|
55
|
-
duplicating logic or writing from scratch.
|
|
98
|
+
duplicating logic or writing from scratch. A shared helper is ONE factory-built object whose interface is declared
|
|
99
|
+
first; it lives in its own `<name>.ts`, with a same-named folder for its types and parts (`/owlmeans-code-structure`). Only write genuinely new code when nothing reusable exists.
|
|
56
100
|
|
|
57
101
|
## 4. Simplify after writing
|
|
58
102
|
|
|
@@ -60,5 +104,7 @@ Once code is written, review it: can it be **shorter, clearer, or expressed with
|
|
|
60
104
|
Lean on framework utilities, remove dead branches, collapse needless indirection. Less code that reuses
|
|
61
105
|
the framework is better than more bespoke code.
|
|
62
106
|
|
|
63
|
-
See `[[
|
|
64
|
-
`
|
|
107
|
+
See `[[scaffolding]]` for how a project is assembled, and `[[agent-skills]]` for keeping the
|
|
108
|
+
deployed skill catalogue current. The package map itself is `tree.md` at the root of the
|
|
109
|
+
[owlmeans/common](https://github.com/owlmeans/common) repository — layer by layer, every package
|
|
110
|
+
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?
|
|
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
|
-
##
|
|
53
|
+
## Skills this project does not own
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
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
|
|
@@ -26,8 +39,8 @@ once; never author a per-agent copy** (`.github/instructions/*.instructions.md`,
|
|
|
26
39
|
|
|
27
40
|
```
|
|
28
41
|
.agents/skills/<name>/
|
|
29
|
-
├── SKILL.md # required — frontmatter + body
|
|
30
|
-
├──
|
|
42
|
+
├── SKILL.md # required — frontmatter + body (a package skill's core)
|
|
43
|
+
├── parts/<part>.md # optional — a package skill's purpose parts, loaded on demand
|
|
31
44
|
└── scripts/ # optional — shell scripts the skill runs
|
|
32
45
|
```
|
|
33
46
|
|
|
@@ -38,20 +51,95 @@ 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 —
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 standard defines: `name`, `description`, `license`,
|
|
84
|
+
`compatibility`, `allowed-tools` and nested `metadata`. `@owlmeans/agent-skills` parses no
|
|
85
|
+
frontmatter; the generator that embeds package guidance reads it. Project-specific keys —
|
|
86
|
+
including the OwlMeans `scope: general` routing marker, which sends a skill to the installer bundle
|
|
87
|
+
rather than to one package — belong under `metadata:`, so a skill stays valid in every agent that
|
|
88
|
+
reads it. The invocation switches sit outside the standard and are written at the top level
|
|
89
|
+
alongside it: `user-invocable` (`false` hides a skill from the `/`
|
|
90
|
+
menu, marking it background knowledge), plus `disable-model-invocation` and `argument-hint`, which
|
|
91
|
+
Claude Code understands. Set any of them only when the skill needs it.
|
|
92
|
+
|
|
93
|
+
## Chunked package skills (parts)
|
|
94
|
+
|
|
95
|
+
A package skill that grows past what one call should carry is split. `SKILL.md` stays the
|
|
96
|
+
**core**, loaded whenever the package is chosen; each `parts/<part>.md` holds ONE purpose, loaded
|
|
97
|
+
only for a call that needs it (selection: the `agent-skills` skill).
|
|
98
|
+
|
|
99
|
+
- **The core** keeps the frontmatter, the `**Install:**` line, the exports, the wiring, any
|
|
100
|
+
`## Target wiring` section (an adoption reads it from the core alone) and the rules every use
|
|
101
|
+
needs. Target ≤ 12 000 chars. It ENDS with a Parts table linking every part:
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
## Parts
|
|
105
|
+
|
|
106
|
+
| Part | Load it when |
|
|
107
|
+
|---|---|
|
|
108
|
+
| [navigation](parts/navigation.md) | building the application shell or its menus |
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- **A part** opens with exactly this frontmatter, then `# @owlmeans/<package> — <part title>` and
|
|
112
|
+
the moved sections:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
---
|
|
116
|
+
name: navigation # = the file stem, [a-z0-9-], unique within the package
|
|
117
|
+
description: The application shell — NavLayout, TopNav/SideNav/MobileNav/Footer, the nav config.
|
|
118
|
+
metadata:
|
|
119
|
+
purposes: navigation, layout, screen # closed vocabulary, comma-separated
|
|
120
|
+
mentions: NavLayout, TopNav, SideNav # symbols and import specifiers that call for it
|
|
121
|
+
---
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- **Size:** the generator warns above 12 000 chars per part and fails above 16 000; it also warns
|
|
125
|
+
about a package-specific skill over 16 000 chars that has no parts.
|
|
126
|
+
- **Purposes** come from a closed vocabulary (`PACKAGE_PURPOSES`, `@owlmeans/llm-common`):
|
|
127
|
+
`view`, `form`, `list`, `detail`, `dialog`, `picker`, `navigation`, `layout`, `screen`,
|
|
128
|
+
`theme`, `feedback`, `state`, `client-api`, `server-api`, `data`, `migration`, `query`, `auth`,
|
|
129
|
+
`consent`, `payment`, `planning`, `job`, `agent`, `config`, `test`, `ops`.
|
|
130
|
+
A value outside it fails the generator. Purposes may stay empty only in a general skill.
|
|
131
|
+
- **Mentions** are distinctive symbols or import specifiers, never common words: a call without a
|
|
132
|
+
focus loads every part whose mention appears in its messages.
|
|
133
|
+
- **Names are unique per package** — a part is addressed as `@owlmeans/<package>#<part>`. Every
|
|
134
|
+
general skill routes to the installer package, so a general skill's part carries the skill's own
|
|
135
|
+
prefix (`code-structure-reference`, never `reference`).
|
|
136
|
+
- **YAML:** a value that starts with `@`, a backtick, `[`, `{`, `*` or `&`, or that contains `: `
|
|
137
|
+
or ` #`, stops parsing — start the mentions with a symbol, not an import specifier.
|
|
138
|
+
- **Splitting moves text, never rewrites it.** Every section lands in the core or in exactly one
|
|
139
|
+
part, each part stands alone for its purpose, and a reference to a moved section names its part
|
|
140
|
+
(see "Organizations" in the `sessions` part).
|
|
141
|
+
- Only `SKILL.md` and `parts/*.md` are embedded into a package; any other file beside them stays in
|
|
142
|
+
the repository, and the generator warns about a root `reference.md`.
|
|
55
143
|
|
|
56
144
|
## Refresh the Claude Code links
|
|
57
145
|
|
|
@@ -61,9 +149,23 @@ After creating, renaming, or deleting a skill, run:
|
|
|
61
149
|
sh .agents/scripts/link-skills.sh
|
|
62
150
|
```
|
|
63
151
|
|
|
64
|
-
It creates `.claude/skills/<name>` → `../../.agents/skills/<name>` for every skill and prunes
|
|
65
|
-
whose skill is gone. The links are gitignored and are recreated at session start
|
|
66
|
-
|
|
152
|
+
It creates `.claude/skills/<name>` → `../../.agents/skills/<name>` for every local skill and prunes
|
|
153
|
+
links whose skill is gone. The links are gitignored and are recreated at session start (a committed
|
|
154
|
+
`SessionStart` hook, and on every install where the project declares a root `prepare` script that
|
|
155
|
+
calls it), but a skill added mid-session is invisible to Claude Code until the script runs.
|
|
156
|
+
|
|
157
|
+
The same script also brings in the skills of everything this project depends on, from whichever of
|
|
158
|
+
two sources applies. In a linked checkout — a repo whose root `package.json` lists an upstream
|
|
159
|
+
repo's packages as workspace entries — it resolves those upstream repos first, recursing into each
|
|
160
|
+
one's own manifest up to four levels, and links the skills from the upstream's own
|
|
161
|
+
`.agents/skills/`. A project that declares no such linked upstream falls back to what a plain npm
|
|
162
|
+
install gives it: the read-only `agent-meta/skills/` copies shipped inside each installed
|
|
163
|
+
`@owlmeans/*` package. Either way the links land in `.agents/linked-skills/<name>` (Copilot, Codex)
|
|
164
|
+
and `.claude/skills/<name>` (Claude Code), with a generated `.agents/linked-skills/INDEX.md` listing
|
|
165
|
+
skill, origin and description. Load one by name exactly like a local skill. A local skill of the
|
|
166
|
+
same name always wins, and a nearer dependency wins over a farther one. The whole
|
|
167
|
+
`.agents/linked-skills/` directory is generated and git-ignored — never edit or commit it, and never
|
|
168
|
+
edit an `agent-meta/` copy: fix the skill in the package that ships it.
|
|
67
169
|
|
|
68
170
|
## Skill vs memory
|
|
69
171
|
|
|
@@ -80,10 +182,26 @@ Never paste memory text into a skill. Memory content enters guidance only as a r
|
|
|
80
182
|
rule — trigger, step, and the failure it prevents, with dates, phase/status markers, versions and
|
|
81
183
|
incident narrative stripped (`memory-promotion` → Distillation).
|
|
82
184
|
|
|
185
|
+
## What may enter AGENTS.md
|
|
186
|
+
|
|
187
|
+
`AGENTS.md` — with every file it `@`-imports and `.agents/memory/MEMORY.md` — is loaded in full in
|
|
188
|
+
every session, so it has a budget: **≤ 40 000 chars**, checked by `sh .agents/scripts/agents-size.sh`
|
|
189
|
+
from the repo root where the repo carries it. A line enters it only as:
|
|
190
|
+
|
|
191
|
+
1. a mandatory rule that must hold before any skill is loaded (git, reporting, environments,
|
|
192
|
+
naming, code structure) — stated in one or two lines, with the detail in a skill;
|
|
193
|
+
2. one line of the package map or the command list;
|
|
194
|
+
3. one line of the skills index: `` - `/name` — when to load it ``, ≤ 160 chars.
|
|
195
|
+
|
|
196
|
+
Everything else is loaded on demand: a subsystem's rules, contracts and failure fingerprints go to
|
|
197
|
+
the skill that governs it, and the outage that taught them to `.agents/memory/`. Never paraphrase a
|
|
198
|
+
skill's `description:` into the index — skills self-describe. A change that would push the file over
|
|
199
|
+
budget shortens or moves an existing line in the same change.
|
|
200
|
+
|
|
83
201
|
## After adding a skill
|
|
84
202
|
|
|
85
203
|
1. If it replaces an ad-hoc `.agents/<topic>.md`, remove that file.
|
|
86
204
|
2. If it distilled memory content into rules, shrink the source `.agents/memory/` node to a
|
|
87
205
|
pointer line (`memory-promotion`) — the memory index does not list skills.
|
|
88
|
-
3.
|
|
206
|
+
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
207
|
4. Run `sh .agents/scripts/link-skills.sh`.
|
|
@@ -0,0 +1,24 @@
|
|
|
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/api/src/models",
|
|
8
|
+
"sources/web/src/screens/about.tsx",
|
|
9
|
+
"sources/web/src/screens/session.tsx"
|
|
10
|
+
],
|
|
11
|
+
"overrides": {
|
|
12
|
+
"README.md": "README.bare.md",
|
|
13
|
+
"sources/common/src/consts.ts": "sources/common/src/consts.bare.ts",
|
|
14
|
+
"sources/common/src/entrypoints.ts": "sources/common/src/entrypoints.bare.ts",
|
|
15
|
+
"sources/common/src/index.ts": "sources/common/src/index.bare.ts",
|
|
16
|
+
"sources/api/src/context.ts": "sources/api/src/context.bare.ts",
|
|
17
|
+
"sources/api/src/entrypoints.ts": "sources/api/src/entrypoints.bare.ts",
|
|
18
|
+
"sources/api/src/types.ts": "sources/api/src/types.bare.ts",
|
|
19
|
+
"sources/web/src/context.ts": "sources/web/src/context.bare.ts",
|
|
20
|
+
"sources/web/src/entrypoints.ts": "sources/web/src/entrypoints.bare.ts",
|
|
21
|
+
"sources/web/src/nav.ts": "sources/web/src/nav.bare.ts",
|
|
22
|
+
"sources/web/src/screens/home.tsx": "sources/web/src/screens/home.bare.tsx"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/template/_gitignore
CHANGED
|
@@ -6,6 +6,14 @@ dist
|
|
|
6
6
|
bun.lock
|
|
7
7
|
bun.lockb
|
|
8
8
|
|
|
9
|
+
# Developer-local environment (LOG_LEVEL, VITE_LOG_LEVEL, …)
|
|
10
|
+
.env
|
|
11
|
+
.env.local
|
|
12
|
+
.env.*.local
|
|
13
|
+
|
|
9
14
|
# Generated Claude Code skill symlinks (canonical skills live in .agents/skills/)
|
|
10
15
|
.claude/skills/*
|
|
11
16
|
!.claude/skills/.gitkeep
|
|
17
|
+
|
|
18
|
+
# Skills linked from upstream repos (generated by .agents/scripts/link-skills.sh)
|
|
19
|
+
.agents/linked-skills/
|
package/template/package.json
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"packageManager": "bun@1.
|
|
6
|
+
"packageManager": "bun@1.4.2",
|
|
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,13 +11,14 @@
|
|
|
11
11
|
"typecheck": "tsc -b"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@owlmeans/
|
|
15
|
-
"@owlmeans/
|
|
14
|
+
"@owlmeans/log": "^0.1.18",
|
|
15
|
+
"@owlmeans/server-app": "^0.1.18",
|
|
16
|
+
"@owlmeans/static-resource": "^0.1.18",
|
|
16
17
|
"__APP_SLUG__-common": "workspace:^"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@owlmeans/dep-config": "^0.1.18
|
|
20
|
-
"@types/node": "^
|
|
20
|
+
"@owlmeans/dep-config": "^0.1.18",
|
|
21
|
+
"@types/node": "^26.6.4",
|
|
21
22
|
"typescript": "^7.0.2"
|
|
22
23
|
}
|
|
23
24
|
}
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { SESSION_ITEMS } from '../../consts.js'
|
|
1
|
+
import { handlers } from '@owlmeans/server-app'
|
|
2
|
+
import { session } from '__APP_SLUG__-common'
|
|
3
|
+
import { makeSessionModel } from '../../models/session.js'
|
|
5
4
|
import type { Context } from '../../types.js'
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const ctx = context as Context
|
|
9
|
-
const { sid } = req.params as SessionParams
|
|
10
|
-
const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
|
|
6
|
+
const handle = handlers<Context>()
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
sessionId: sid,
|
|
15
|
-
text: payload.text,
|
|
16
|
-
createdAt: new Date().toISOString(),
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return await resource.create(item)
|
|
20
|
-
})
|
|
8
|
+
export const add = handle.body(session.add, async (payload, context, request) =>
|
|
9
|
+
await makeSessionModel(context, request.params.sid).add(payload.text))
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { handlers } from '@owlmeans/server-app'
|
|
2
|
+
import { session } from '__APP_SLUG__-common'
|
|
3
|
+
import { makeSessionModel } from '../../models/session.js'
|
|
4
4
|
import type { Context } from '../../types.js'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const ctx = context as Context
|
|
8
|
-
const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
|
|
6
|
+
const handle = handlers<Context>()
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return items
|
|
13
|
-
.filter(item => item.sessionId === params.sid)
|
|
14
|
-
.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1))
|
|
15
|
-
})
|
|
8
|
+
export const list = handle.params(session.list, async (params, context) =>
|
|
9
|
+
await makeSessionModel(context, params.sid).list())
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { handlers } from '@owlmeans/server-app'
|
|
2
|
+
import { session } from '__APP_SLUG__-common'
|
|
3
|
+
import { makeSessionModel } from '../../models/session.js'
|
|
4
4
|
import type { Context } from '../../types.js'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const ctx = context as Context
|
|
8
|
-
const resource = ctx.getStaticResource<SessionItem>(SESSION_ITEMS)
|
|
6
|
+
const handle = handlers<Context>()
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (existing == null || existing.sessionId !== params.sid) {
|
|
13
|
-
return { removed: false }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
await resource.delete(params.id)
|
|
17
|
-
return { removed: true }
|
|
18
|
-
})
|
|
8
|
+
export const remove = handle.params(session.remove, async (params, context) =>
|
|
9
|
+
await makeSessionModel(context, params.sid).remove(params.id))
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { config } from '@owlmeans/server-app'
|
|
2
2
|
import { APP_API, commonConfig } from '__APP_SLUG__-common'
|
|
3
3
|
import type { Config } from './types.js'
|
|
4
|
+
// The module augmentation that gives the config its `log` field — a side-effect import only.
|
|
5
|
+
import type {} from '@owlmeans/log'
|
|
4
6
|
|
|
5
7
|
// The server listens on the APP_API service route's port (3000), declared in common/config.ts.
|
|
6
8
|
const cfg = config<Config>(APP_API, commonConfig as Config)
|
|
7
9
|
|
|
10
|
+
// The log level comes from the runtime environment, never from code: `info` unless LOG_LEVEL
|
|
11
|
+
// says otherwise; LOG_DEBUG lists scopes forced to debug (`*` for all). Bun reads
|
|
12
|
+
// `sources/api/.env` on its own.
|
|
13
|
+
cfg.log = { level: process.env.LOG_LEVEL || 'info', debug: process.env.LOG_DEBUG ?? '' }
|
|
14
|
+
|
|
8
15
|
export default cfg
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { makeContext as makeBasicContext } from '@owlmeans/server-app'
|
|
2
|
+
import type { Config, Context } from './types.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where the app's resources are registered. `@owlmeans/static-resource` is already a dependency,
|
|
6
|
+
* so `appendStaticResource<C, T>(context, ALIAS)` gives you an in-memory store with no database
|
|
7
|
+
* behind it; a mongo/postgres resource takes its place once the data has to outlive the process.
|
|
8
|
+
* Whatever you append here must also widen `Context` in `types.ts`, or the getter will not exist.
|
|
9
|
+
*/
|
|
10
|
+
export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T =>
|
|
11
|
+
makeBasicContext<C, T>(cfg, true)
|
|
@@ -10,9 +10,5 @@ export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T =
|
|
|
10
10
|
// data lives in process memory and is cleared when the api restarts.
|
|
11
11
|
appendStaticResource<C, T>(context, SESSION_ITEMS)
|
|
12
12
|
|
|
13
|
-
// A child context has to inherit THIS factory, not the layer's — otherwise a derived context
|
|
14
|
-
// is built without the resource registered above and every lookup on it throws.
|
|
15
|
-
context.makeContext = makeContext as typeof context.makeContext
|
|
16
|
-
|
|
17
13
|
return context
|
|
18
14
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { entrypoints } from '@owlmeans/server-app'
|
|
2
|
+
import { bind } from '@owlmeans/server-entrypoint'
|
|
3
|
+
import { appProtocols } from '__APP_SLUG__-common'
|
|
4
|
+
import * as handlers from './app/session/index.js'
|
|
5
|
+
|
|
6
|
+
/** Local server bindings for the shared session protocol tree. */
|
|
7
|
+
export const appBindings = [
|
|
8
|
+
...entrypoints,
|
|
9
|
+
bind(appProtocols.api.session.base),
|
|
10
|
+
bind(appProtocols.api.session.list, handlers.list),
|
|
11
|
+
bind(appProtocols.api.session.add, handlers.add),
|
|
12
|
+
bind(appProtocols.api.session.remove, handlers.remove),
|
|
13
|
+
]
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { logger } from '@owlmeans/log'
|
|
1
2
|
import { main } from '@owlmeans/server-app'
|
|
2
3
|
import config from './config.js'
|
|
3
4
|
import { makeContext } from './context.js'
|
|
4
|
-
import {
|
|
5
|
+
import { appBindings } from './entrypoints.js'
|
|
5
6
|
import type { Config, Context } from './types.js'
|
|
6
7
|
|
|
8
|
+
const log = logger('api')
|
|
9
|
+
|
|
7
10
|
const context = makeContext<Config, Context>(config)
|
|
8
11
|
|
|
9
|
-
main<{}, Config, Context>(context,
|
|
12
|
+
main<{}, Config, Context>(context, appBindings).catch(error => {
|
|
13
|
+
log.error('Start failed', error)
|
|
14
|
+
process.exit(1)
|
|
15
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SessionItem } from '__APP_SLUG__-common'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The items of ONE browser session. The session id is bound when the model is built, so no
|
|
5
|
+
* member can reach another session's items; the member names are the session endpoints' keys.
|
|
6
|
+
*/
|
|
7
|
+
export interface SessionModel {
|
|
8
|
+
/** This session's items, newest first. */
|
|
9
|
+
list: () => Promise<SessionItem[]>
|
|
10
|
+
/** Store a new item under this session. */
|
|
11
|
+
add: (text: string) => Promise<SessionItem>
|
|
12
|
+
/** Remove an item — only when it belongs to this session. */
|
|
13
|
+
remove: (id: string) => Promise<{ removed: boolean }>
|
|
14
|
+
}
|