@synap-core/workspace-templates 0.24.0 → 0.25.0

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 CHANGED
@@ -21,10 +21,10 @@ How installs, reconciles and tiers work is in the `synap-market` skill
21
21
  | Dir | Kind | Format | Published today? |
22
22
  |---|---|---|---|
23
23
  | `src/*.yaml` | `workspace` (and `pack`, for a suite) | Legacy workspace YAML (`meta:` plus body). A thin adapter reads it as `{kind: workspace, meta, spec}` | Yes. 31 entries, CI on every push to main |
24
- | `capabilities/<key>.capability.json` | `capability` | Manifest (below). `meta` carries the listing and visibility; `spec` is the CapabilityDefinition | Yes, by hand. CI also publishes it once `SYNAP_CATALOG_LIVE_KINDS` includes `capability` (§3) |
25
- | `skills/<slug>/` | `skill` | Either a manifest `<slug>.skill.json` (`creative-director`), or an Agent-Skills folder (`SKILL.md` plus references) with a header `skills/<slug>.catalog.json` beside it | The manifest: yes. A folder: only with its header, and only when it holds no reference files (a skill package carries no documents). Today one folder has a header (`designing-with-real-components`); the five moved folders have none and are **staged** |
26
- | `views/<slug>.view.json` | `view` | Manifest; `spec.views` in the canonical shape the CP stores (`{slug, displayName, type, config, scopeProfileSlugs}`) | Category `view`. Three today (`bookmark-views-pack`, `event-views-pack`, `task-views-pack`), moved from the old CP pack fragments on 2026-11-05. CI writes them once `SYNAP_CATALOG_LIVE_KINDS` includes `view` |
27
- | `automations/<slug>.automation.json` | `automation` | bridge-setup `flowDefinition` form, plus a header `automations/<slug>.catalog.json` beside it | Only with its header, and only without apply-time placeholders. Today none has a header, so all three are **staged** (`mail-feed` also carries two placeholders bridge-setup fills) |
24
+ | `capabilities/<key>.capability.json` | `capability` | Manifest (below). `meta` carries the listing and visibility; `spec` is the CapabilityDefinition | Yes, CI on every push to main (§4) |
25
+ | `skills/<slug>/` | `skill` | Either a manifest `<slug>.skill.json` (`creative-director`), or an Agent-Skills folder (`SKILL.md` plus references) with a header `skills/<slug>.catalog.json` beside it | The manifest: yes. A folder: only with its header, and only when it holds no reference files (a skill package carries no documents). Headers decided by the founder on 2026-11-05: `bookmark-enrichment` and `routing-to-channels` public, `mapping-the-server` unlisted (private to the official owner); `reading-client-progress` and the parked `stellar-scf-grants-advisor` stay **staged** |
26
+ | `views/<slug>.view.json` | `view` | Manifest; `spec.views` in the canonical shape the CP stores (`{slug, displayName, type, config, scopeProfileSlugs}`) | Category `view`. Three today (`bookmark-views-pack`, `event-views-pack`, `task-views-pack`), moved from the old CP pack fragments on 2026-11-05. CI on every push to main |
27
+ | `automations/<slug>.automation.json` | `automation` | bridge-setup `flowDefinition` form, plus a header `automations/<slug>.catalog.json` beside it | Only with its header, and only without apply-time placeholders. Headers decided by the founder on 2026-11-05: `bookmark-enrichment` public; `url-bookmark-capture`, `github-pr-events` and the five `ship-a-change-*` unlisted. `mail-feed` stays **staged**: it carries two placeholders bridge-setup fills |
28
28
  | `schema/` | | Zod manifest schema: `header.ts`, plus one body per kind (`workspace`, `capability`, `skill`, `automation`, `playbook`) | |
29
29
  | `standards/*.standard.yaml` | | Quality standard per workspace (`pnpm eval`) | |
30
30
  | `scripts/catalog-lib.mjs` | | **The ONE lib**: `loadCatalog` → `validateCatalog` → `diffCatalog` → `publishCatalog` | |
@@ -86,12 +86,8 @@ only when it is strictly newer than their bundle.
86
86
 
87
87
  **Capability.** Edit `capabilities/<key>.capability.json`. The listing and
88
88
  visibility go in `meta`; the definition goes in `spec`.
89
- - **Transition:** an **existing** capability also has a CP copy,
90
- `synap-control-plane-api/src/seeds/capability-templates/<key>.capability.json`,
91
- whose content must equal `spec`. Its header lives in `capability-listings.ts` and
92
- `CAPABILITY_VISIBILITY` in the seeder, and must equal `meta`. Change both sides.
93
- The CP tripwire `catalog-mirror.tripwire.test.ts` turns red otherwise.
94
- - A **new** capability is authored here only: catalog-only files are allowed.
89
+ - This file is the only copy. The CP's insert-only bootstrap reads this package's
90
+ `capabilities/` (installed from npm); it holds no copy of its own.
95
91
  - **A reader** is an ordinary verb that reads one link: `intent: "read_webpage"`, `metadata.readOnly: true`,
96
92
  a required `url` parameter, and `urls: [...]` declaring the links it handles (`host[/path]`, `*.host`,
97
93
  or `"*"`; the grammar lives in `@synap-core/types/url-read`). The pod's one read door routes by those
@@ -121,12 +117,9 @@ folder (`skill-documents`), `metadata.auto_load: true` (`skill-auto-load`), a
121
117
  frontmatter name that is not `meta.slug` (`skill-slug`). Without a header the folder
122
118
  is staged. Deciding which folders get a header (their listing and visibility) is a
123
119
  content decision; `reading-client-progress` and `stellar-scf-grants-advisor` are
124
- client-specific.
125
- - **Transition:** the five moved folders (`bookmark-enrichment`,
126
- `mapping-the-server`, `reading-client-progress`, `routing-to-channels`,
127
- `stellar-scf-grants-advisor`) must stay byte-identical to
128
- `synap-cli/templates/skills/<slug>/`, because `bridge-setup` still reads them
129
- there. The guard is the CLI's `test/catalog-mirror.tripwire.test.ts`.
120
+ client-specific. A private (unlisted) header carries `"isPublic": false, "owner":
121
+ "template-owner"`. `synap bridge-setup` reads these folders from the installed
122
+ package; the CLI holds no copy (synap-cli#91).
130
123
 
131
124
  **View.** Add or edit `views/<slug>.view.json`:
132
125
 
@@ -154,8 +147,9 @@ description?, triggerType, triggerConfig, flowDefinition, status }] }`, i.e. the
154
147
  file minus its `metadata` notes. Refused: an apply-time placeholder
155
148
  (`apply-time-placeholder`: an empty or `<…>` connection id, a `<…>` output channel,
156
149
  a skill node without `skillId`) and any raw key a package cannot carry (`state`).
157
- Transition: the three raw files must stay byte-identical to
158
- `synap-cli/templates/automations/` (CLI tripwire).
150
+ `synap bridge-setup` reads `bookmark-enrichment`, `mail-feed` and
151
+ `url-bookmark-capture` from the installed package; the CLI holds no copy
152
+ (synap-cli#91).
159
153
 
160
154
  **Every kind.** Run the gate before you push:
161
155
 
@@ -350,12 +344,11 @@ wrapper `scripts/publish-official.mjs`, which uses the same lib):
350
344
  | Event | What runs |
351
345
  |---|---|
352
346
  | PR touching the catalog | Job `validate` only: build, validate every kind, print the **offline** preview (each entry and the version the CP will derive, where knowable offline). It holds **no secret and no `id-token`**: a PR runs its own lockfile and scripts. Guarded by `scripts/publish-workflow.guard.test.ts`. |
353
- | Push to `main` (or manual) | `validate`, then job `publish` (environment `catalog-publish`): a read-only preview against the live CP, then publish live `--kind ${SYNAP_CATALOG_LIVE_KINDS:-workspace}`, then npm publish, only if the `package.json` version is new on npm. |
347
+ | Push to `main` (or manual) | `validate`, then job `publish` (environment `catalog-publish`): a read-only preview against the live CP, then publish EVERY kind live (no `--kind`), tombstones included, then npm publish, only if the `package.json` version is new on npm. |
354
348
 
355
- `SYNAP_CATALOG_LIVE_KINDS` is a repository **variable**. While it is unset, main
356
- publishes workspaces only: every kind is still validated and previewed, but only
357
- workspaces are written. Set it to `workspace,capability,skill,pack,automation,view`
358
- only after runbook §5 A. Secrets: `SYNAP_CP_URL`, `SYNAP_CP_PUBLISH_TOKEN`
349
+ Main publishes every kind (founder, 2026-11-05: "remove the blocker that only do
350
+ workspace, we will do ALL"); the old `SYNAP_CATALOG_LIVE_KINDS` variable is not
351
+ read. Secrets: `SYNAP_CP_URL`, `SYNAP_CP_PUBLISH_TOKEN`
359
352
  (a CP PAT of the `synap-official` owner; humans use `synap login`), `NPM_TOKEN`.
360
353
 
361
354
  **One-time setup of the `catalog-publish` environment** (GitHub → synap-app →
@@ -377,18 +370,13 @@ row. A tripwire (`no-template-reseed-on-deploy-tripwire.test.ts`) guards this.
377
370
  key gets 409 `OFFICIAL_CAPABILITY_KEY_RESERVED`, and the CP serves the official row
378
371
  first for a key.
379
372
 
380
- **Transition mirrors** (each retires in the same change that deletes its copies; see §5).
381
- These guards are **local-only**: each skips when the sibling repo is not checked out,
382
- and every repo's CI checks out itself alone, so CI does not enforce them. Run them
383
- on a full monorepo checkout before merging a change to either side. The same holds
384
- for `schema/header.mirror.tripwire.test.ts` (header limits ↔ the CP `publishSchema`)
385
- and `scripts/catalog-lib.columns.tripwire.test.ts` (the preview's columns and
386
- adoption rule ↔ the CP publish core); their CI-safe halves are snapshots.
387
-
388
- | Copy | Guard | Retires when |
389
- |---|---|---|
390
- | ~~CP `src/seeds/capability-templates/`, `templates/packs/`~~ | | **Retired 2026-11-05** (founder: one source). The CP seeders read the installed package; its tripwire `no-catalog-copy.tripwire.test.ts` fails on any copy |
391
- | CLI `templates/skills/<5 moved>/`, `templates/automations/*.automation.json` | CLI `test/catalog-mirror.tripwire.test.ts` (byte-equal, both directions) | the CLI's pin admits a package release that ships them: `bridge-setup` already reads the installed package first, and the CLI's retirement test fails while both exist |
373
+ **No copies.** Since 2026-11-05 (founder: "keep one source only") neither the CP
374
+ nor the CLI holds a copy of any catalog file: both read this package from npm. The
375
+ CP's `no-catalog-copy.tripwire.test.ts` fails on a copy there. Two cross-repo guards
376
+ stay **local-only** (they skip when the CP is not a sibling checkout):
377
+ `schema/header.mirror.tripwire.test.ts` (header limits ↔ the CP `publishSchema`) and
378
+ `scripts/catalog-lib.columns.tripwire.test.ts` (the preview's columns and adoption
379
+ rule ↔ the CP publish core); their CI-safe halves are snapshots.
392
380
 
393
381
  ## 5. Founder runbook: deploy, publish, retire the copies
394
382
 
@@ -454,13 +442,10 @@ Do these in order. The runbook only names the commands; it does not run anything
454
442
  `description` (the catalog's copy, which never reached the CP), `source:
455
443
  "file-seed" → "api"` and `vendorId: null → synap-official` (the publish adopts
456
444
  the unowned seeded row). The views themselves are byte-equal to the live rows.
457
- Then publish the same three slugs with `synap catalog publish --official`.
458
- 8. **Widen CI:** set the repo variable
459
- `SYNAP_CATALOG_LIVE_KINDS=workspace,capability,skill,automation,view`. A skill
460
- folder or raw automation publishes only once it has a header.
461
- 9. On a **brand-new, empty** CP only: run
445
+ CI publishes them with every other kind on the next push to main.
446
+ 8. On a **brand-new, empty** CP only: run
462
447
  `docker compose -f docker-compose.prod.yml run --rm control-plane pnpm seed:capabilities`
463
- (and `seed:templates`) once, then step 6 and step 7. `seed:templates` seeds
448
+ (and `seed:templates`) once, then publish (step 6). `seed:templates` seeds
464
449
  workspaces only: views reach an empty CP through the publish.
465
450
 
466
451
  ### B. Publish the package and retire the mirrors
@@ -480,13 +465,12 @@ Do these in order. The runbook only names the commands; it does not run anything
480
465
  - the CP seeder and capability resolver (`capability-template-dir.ts`) read
481
466
  `node_modules/@synap-core/workspace-templates/capabilities/` (done 2026-11-05;
482
467
  `seed-templates.ts` no longer seeds packs: views publish through the door);
483
- - `synap bridge-setup` installs the published skill and automation entries
484
- through the pod instead of reading `templates/`.
468
+ - `synap bridge-setup` reads the skill and automation files from the installed
469
+ package (done, synap-cli#91).
485
470
  4. **Delete the copies and their tripwires in the same change:**
486
471
  - CP: done 2026-11-05 (copies, listing and visibility literals, and both
487
472
  tripwires deleted);
488
- - CLI: the five moved skill folders, `templates/automations/`, and
489
- `test/catalog-mirror.tripwire.test.ts`.
473
+ - CLI: done (synap-cli#91).
490
474
 
491
475
  ### C. Coordinated rename (planned)
492
476
 
@@ -0,0 +1,16 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "bookmark-enrichment-auto",
6
+ "name": "Bookmark enrichment (auto)",
7
+ "description": "When a bookmark is saved, enrich it: what the pod already connects to it first, then the page itself, classified and linked into the graph.",
8
+ "tags": [
9
+ "automation",
10
+ "bookmarks",
11
+ "enrichment"
12
+ ],
13
+ "isPublic": true
14
+ },
15
+ "dependencies": []
16
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "github-pr-events",
6
+ "name": "GitHub pull requests and checks to dev-loop facts",
7
+ "description": "Reads the GitHub org webhook (one inbound source named GitHub) and records what happened as dev-loop observations: a pull request opened or reopened → dev.pr_opened, merged → dev.pr_merged, closed unmerged → dev.pr_closed; a check suite completed → ci.finished. The pod's own consumers (the merge sweeper, the Ship a change automations) take it from there.",
8
+ "tags": [
9
+ "automation",
10
+ "github",
11
+ "dev-loop",
12
+ "builder"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "ship-a-change-checks-green",
6
+ "name": "CI green to Ship a change waits on the merge",
7
+ "description": "When a CI run on a pull request's head finishes green, grade the session's checks-green criterion and move its Ship a change step to Merged.",
8
+ "tags": [
9
+ "automation",
10
+ "dev-loop",
11
+ "builder",
12
+ "ship-a-change"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "ship-a-change-checks-red",
6
+ "name": "CI red to Ship a change goes back to Building",
7
+ "description": "When a CI run on a pull request's head fails, grade the session's checks-green criterion as failed and send its Ship a change step back to Building (the Checks green stage's onFail).",
8
+ "tags": [
9
+ "automation",
10
+ "dev-loop",
11
+ "builder",
12
+ "ship-a-change"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "ship-a-change-deployed",
6
+ "name": "Deployed to the devbox worker dogfoods it",
7
+ "description": "When this pod reports a new build live (dev.deployed, recorded by the pod itself after a successful update), start a Dogfood a change run handed to the devbox worker, filed into the goal.",
8
+ "tags": [
9
+ "automation",
10
+ "dev-loop",
11
+ "builder",
12
+ "ship-a-change"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "ship-a-change-pr-merged",
6
+ "name": "PR merged to Ship a change waits on the lab deploy",
7
+ "description": "When a PR merges: the merge sweeper (built in, backend#283) already marks the session's pr-* outcome met. This automation grades the session's `merged` criterion and moves its Ship a change step to Deployed to lab, where the person approves the deploy.",
8
+ "tags": [
9
+ "automation",
10
+ "dev-loop",
11
+ "builder",
12
+ "ship-a-change"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "ship-a-change-pr-opened",
6
+ "name": "PR opened to Ship a change waits on its checks",
7
+ "description": "When a pull request opens with a `Pod session:` line, grade the session's pr-opened criterion and move its Ship a change step to Checks green.",
8
+ "tags": [
9
+ "automation",
10
+ "dev-loop",
11
+ "builder",
12
+ "ship-a-change"
13
+ ],
14
+ "isPublic": false,
15
+ "owner": "template-owner"
16
+ },
17
+ "dependencies": []
18
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "apiVersion": "synap/v1",
3
+ "kind": "automation",
4
+ "meta": {
5
+ "slug": "url-bookmark-capture",
6
+ "name": "Discord links to bookmarks",
7
+ "description": "Every link posted in a Discord message becomes a bookmark, with the message's context kept. No AI.",
8
+ "tags": [
9
+ "automation",
10
+ "bookmarks",
11
+ "discord"
12
+ ],
13
+ "isPublic": false,
14
+ "owner": "template-owner"
15
+ },
16
+ "dependencies": []
17
+ }