@mnstry/atelier 0.2.0-alpha.4 → 0.2.0-alpha.5

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 (53) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +38 -12
  3. package/contracts/public-api-baseline.json +57 -0
  4. package/docs/assurance-controls.md +39 -0
  5. package/docs/atelier-runtime.md +15 -0
  6. package/docs/blocks/claims.md +15 -9
  7. package/docs/design.md +12 -6
  8. package/docs/install.md +26 -4
  9. package/docs/knowledge-graph.md +8 -4
  10. package/docs/local-services.md +101 -0
  11. package/docs/release-engineering.md +75 -10
  12. package/docs/repo-boundary-guard.md +12 -2
  13. package/docs/upgrade.md +25 -2
  14. package/fixtures/projects/sample-workspace/content/source.html.kg.json +4 -1
  15. package/fixtures/projects/source-formats-workspace/content/data.json.kg.json +4 -1
  16. package/fixtures/projects/source-formats-workspace/content/logo.png.kg.json +4 -1
  17. package/fixtures/projects/source-formats-workspace/content/metrics.csv.kg.json +4 -1
  18. package/fixtures/projects/source-formats-workspace/content/pipeline.yaml.kg.json +4 -1
  19. package/package.json +12 -5
  20. package/skills/claude/atelier-local-service/SKILL.md +47 -0
  21. package/skills/claude/atelier-public-boundary/SKILL.md +31 -0
  22. package/skills/codex/atelier-local-service/SKILL.md +47 -0
  23. package/skills/codex/atelier-public-boundary/SKILL.md +31 -0
  24. package/src/boundary/content-rules.mjs +278 -20
  25. package/src/boundary/policy.mjs +150 -60
  26. package/src/cli/execute-command.mjs +36 -0
  27. package/src/cli/run.mjs +17 -7
  28. package/src/collaboration/event-ledger.mjs +365 -0
  29. package/src/collaboration/index.mjs +17 -0
  30. package/src/collaboration/proposals.mjs +265 -65
  31. package/src/commands/attestation.mjs +20 -6
  32. package/src/commands/disclosure.mjs +133 -0
  33. package/src/commands/distribution.mjs +2 -1
  34. package/src/commands/extension-pack.mjs +2 -1
  35. package/src/commands/init.mjs +2 -1
  36. package/src/commands/server.mjs +1 -4
  37. package/src/disclosure/content-scan.mjs +193 -0
  38. package/src/egress/check.mjs +7 -38
  39. package/src/egress/forbidden-egress.mjs +32 -18
  40. package/src/graph/graph.mjs +112 -314
  41. package/src/graph/knowledge-graph.mjs +94 -18
  42. package/src/harness/context-client.mjs +9 -1
  43. package/src/index.mjs +12 -0
  44. package/src/project/config.mjs +66 -7
  45. package/src/project/file-class.mjs +14 -0
  46. package/src/project/package-root.mjs +10 -0
  47. package/src/project/path-match.mjs +38 -15
  48. package/src/project/private-state.mjs +110 -0
  49. package/src/server/local-sidecar.mjs +81 -59
  50. package/src/server/security.mjs +89 -4
  51. package/src/server/server.mjs +3 -2
  52. package/src/support/feedback-report.mjs +4 -3
  53. package/src/upgrade/upgrade.mjs +2 -1
@@ -10,16 +10,23 @@ a location, never the matched content.
10
10
  ### release:audit
11
11
 
12
12
  `npm run release:audit` (`scripts/check-release-tarball.mjs`) audits the exact
13
- tarball `npm pack` would publish:
13
+ tarball `npm pack` would publish. `npm run release:candidate` packs once and
14
+ passes the same archive and expected SHA-256 through this audit and both
15
+ consumer smokes:
14
16
 
15
17
  - Package metadata: name, license, exposed CLI bins, and a mandatory `files`
16
18
  allowlist in `package.json`.
17
19
  - Tarball allowlist: every packed path must match a known-good pattern; any
18
- unexpected file fails the audit.
20
+ unexpected file fails the audit. The extracted archive inventory must match
21
+ the `npm pack --json` inventory exactly.
19
22
  - Content scan: every packed file is scanned against committed structural
20
23
  patterns (absolute user paths, machine-local temp paths, agent-local state
21
24
  paths, key material, secret-like assignments) and against the maintainer-held
22
25
  denylist described below.
26
+ - Egress scan: the canonical egress control receives the exact `npm pack`
27
+ inventory and inspects every packed executable or markup file, including a
28
+ test-shaped path if one is ever admitted to the artifact. Packed test-fixture
29
+ suppression markers are refused; reviewed local-computed markers are counted.
23
30
  - Version drift: `CHANGELOG.md` must contain a `## <version>` heading and
24
31
  `README.md` must mention the version. The expected version and tarball name
25
32
  are derived from `package.json`, never hardcoded.
@@ -27,6 +34,15 @@ tarball `npm pack` would publish:
27
34
  Exit codes: `0` clean, `1` findings, `2` configuration error (for example an
28
35
  unavailable denylist without explicit acknowledgment).
29
36
 
37
+ `release:candidate` additionally requires a clean tree, records the candidate
38
+ commit and tarball digest, and refuses a version already bound to a different
39
+ tagged commit. It is a release-evidence command, not a publication command.
40
+ When `ATELIER_RELEASE_OUTPUT_DIR` is set, it atomically retains the verified
41
+ tarball, npm-pack metadata, and a machine-readable receipt. The trusted
42
+ publishing workflow runs `prepublishOnly` explicitly with that output directory,
43
+ re-verifies the retained digest, and publishes the retained tarball path rather
44
+ than repacking the source checkout.
45
+
30
46
  ### repo:check
31
47
 
32
48
  `npm run repo:check` (`scripts/check-repo-disclosure.mjs`) sweeps the whole
@@ -43,6 +59,27 @@ Git-tracked tree, not just the tarball:
43
59
  Exit codes match `release:audit`: `0` clean, `1` findings, `2` configuration or
44
60
  usage error.
45
61
 
62
+ ### disclosure check
63
+
64
+ `atelier disclosure check` is the portable consumer-facing content gate. It
65
+ scans every tracked text file by default or the exact staged index with
66
+ `--staged`, never follows tracked symlinks, and reports labels plus locations
67
+ without echoing matched content. `--untrusted` suppresses finding details.
68
+
69
+ The command loads private patterns from `ATELIER_DENYLIST_JSON`, an explicit
70
+ `--denylist` path, or ignored
71
+ `.atelier-local/disclosure-denylist.json`. A repository-local denylist is
72
+ refused if it is tracked or not covered by `.gitignore`. Missing private
73
+ patterns are a configuration failure unless `--structural-only` explicitly
74
+ acknowledges the reduced verdict. Public text-only packaging can also use
75
+ `--fail-on-binary`; Atelier's own tarball audit separately refuses packed
76
+ binary files.
77
+
78
+ The public Atelier repository keeps the stronger `repo:check` identity and
79
+ commit-message controls. The portable command exists so consumer repositories
80
+ can enforce the same public/private content boundary without inheriting
81
+ MNSTRY-specific commit identities.
82
+
46
83
  ### Commit-identity gate
47
84
 
48
85
  Part of `repo:check --commits`. Commit authors must match a hardcoded
@@ -65,6 +102,17 @@ changelog and the migration registry honest about breaking changes:
65
102
  - Every registered migration record is re-validated against the migration
66
103
  record contract.
67
104
 
105
+ ### public-api:compat
106
+
107
+ `npm run public-api:compat` compares every package subpath and named JavaScript
108
+ export published by `v0.2.0-alpha.4` with the current package. Removing one
109
+ fails closed. It also rejects modified source that retains the already-tagged
110
+ baseline version, independently of the release-candidate check. The baseline
111
+ records and verifies its tag commit and the public npm artifact identity; the
112
+ published archive was independently checked to contain all 20 subpaths and 212
113
+ named exports. This is runtime JavaScript shape continuity, not a promise about
114
+ function signatures, types, or behavior.
115
+
68
116
  ### egress:check
69
117
 
70
118
  `npm run egress:check` (`atelier egress check`) scans package runtime paths for
@@ -75,8 +123,22 @@ paths; this gate is the mechanical check behind that claim.
75
123
 
76
124
  `npm run consumer:smoke` (`scripts/consumer-smoke.mjs`) packs the real tarball,
77
125
  installs it offline into a throwaway consumer project with lifecycle scripts
78
- disabled, and imports the public API to validate a sample export. It proves the
79
- tarball is installable and functional exactly as a consumer receives it.
126
+ disabled and without copying the publisher's `overrides`, checks the installed
127
+ dependency tree, imports every declared JavaScript export, parses every
128
+ declared JSON export, and validates a sample export through both API and CLI.
129
+ It proves the tarball is installable and functional exactly as a bare consumer
130
+ receives it from disk. The offline smoke deliberately warms the locked registry
131
+ dependency closure first; it does not prove that a not-yet-published version
132
+ resolves from a cold or live registry.
133
+
134
+ ### assurance:mutation-smoke
135
+
136
+ `npm run assurance:mutation-smoke` runs local, synthetic negative controls for
137
+ the boundary, graph, packed and direct egress, sidecar, and distribution
138
+ families. Every fixture introduces one named failure and must be refused by the
139
+ terminal CLI or release command where one exists. This is part of
140
+ `prepublishOnly`; a control that stops detecting its failure mode blocks the
141
+ release even if positive-path tests remain green.
80
142
 
81
143
  ### Egress-marker inventory
82
144
 
@@ -105,7 +167,7 @@ maintainer-reviewed before entering the list.
105
167
  Four jobs run on pushes to `main` and on pull requests, and all four are
106
168
  required status checks:
107
169
 
108
- - `test`: syntax check (`node --check`, not a type system), the full test suite, contract checks, `egress:check`, and
170
+ - `test`: syntax check (`node --check`, not a type system), the full test suite (including isolated consumer disclosure-command proofs), contract checks, `egress:check`, `assurance:mutation-smoke`, and
109
171
  `migrations:check`. This job sets `ATELIER_ALLOW_MISSING_DENYLIST=1` scoped
110
172
  to the job only — denylist assertions belong to the secret lane.
111
173
  - `consumer-smoke`: warms the npm cache with `npm ci` (the offline tarball
@@ -127,11 +189,14 @@ the only safe block.
127
189
 
128
190
  To clear a fork pull request, a maintainer verifies the head SHA and dispatches
129
191
  the `fork-sweep` workflow with the pull-request number and that SHA. The
130
- workflow runs the trusted scanner from `main` against the fork's tree checked
131
- out as data — it never installs or executes anything from the untrusted tree —
132
- re-verifies that the head SHA has not moved, and posts a `secret-sweep` check
133
- run on the SHA. The newest check run with that name supersedes the earlier
134
- failure for branch protection.
192
+ workflow pins the trusted scanner checkout to the protected default branch and
193
+ runs it against the fork checked out as data — it never installs or executes
194
+ anything from the untrusted tree. It requires an open PR whose base repository
195
+ and branch are the protected default, pins the base and head SHAs from GitHub,
196
+ scans the complete bounded base-to-head object range while waiving only
197
+ repository-specific commit identity, re-verifies that the head SHA has not
198
+ moved, and posts a `secret-sweep` check run on the SHA. The newest check run
199
+ with that name supersedes the earlier failure for branch protection.
135
200
 
136
201
  `release:audit` never runs against untrusted code (`npm pack` executes
137
202
  lifecycle scripts); it re-runs on the push build of the merge commit. No
@@ -170,12 +170,22 @@ machine for weeks.
170
170
  - `pre-push` runs `atelier boundary push-check` — git writes the ref updates to
171
171
  the hook's stdin, and only that range is judged. A brand-new branch is diffed
172
172
  against the empty tree, so nothing slips through unscanned.
173
- - `atelier boundary audit` scans the whole tree and **reports without blocking**,
174
- listing both matches and declared exceptions with their reasons.
173
+ - `atelier boundary audit` scans the current working tree by default and
174
+ **reports without blocking**, listing matches, incomplete-read diagnostics,
175
+ and declared exceptions with their reasons. Use `--head` for a committed
176
+ snapshot. The output names its source so a dirty tree cannot be mistaken for
177
+ `HEAD` evidence.
175
178
 
176
179
  If the guard cannot work out which repo it is running in, it fails closed. A
177
180
  guard that silently judges nothing is worse than one that stops you.
178
181
 
182
+ Path scopes are segment-aware globs: `*` does not cross `/`, `**` does, and
183
+ patterns are matched against normalized repository-relative paths. Explicitly
184
+ declaring `contentRules: []` is invalid; omit the field to receive defaults.
185
+ Git diff output and binary reads have per-file and aggregate budgets. A failed,
186
+ truncated, oversized, or unparsable evidence read produces a blocking
187
+ completeness diagnostic rather than a partial clean verdict.
188
+
179
189
  ### Declaring an exception
180
190
 
181
191
  Exceptions live in the boundary policy, not in the guard script. A repo-specific
package/docs/upgrade.md CHANGED
@@ -5,6 +5,29 @@ workspace between Atelier package releases. The flow is local-only: it does not
5
5
  provision repositories, contact a Git host, mutate the MNSTRY runtime, or write
6
6
  through a browser view.
7
7
 
8
+ ## Upgrading to 0.2.0-alpha.5
9
+
10
+ This release hardens public/private boundary enforcement, local serving,
11
+ collaboration-ledger integrity, disclosure review, and release provenance.
12
+ Documents valid against `0.2.0-alpha.0` remain contract-compatible, but some
13
+ previously tolerated unsafe or ambiguous states now fail closed.
14
+
15
+ - Projects using `atelier dev` must provide a generated
16
+ `atelier.manifest.json`; only enrolled, safe, realpath-validated static files
17
+ are served, and the sidecar accepts loopback traffic only.
18
+ - Empty or malformed content-rule policies, incomplete Git reads, corrupt or
19
+ oversized collaboration ledgers, and unsafe manifest entries are now
20
+ blocking errors with typed CLI diagnostics.
21
+ - Run `atelier disclosure check` before sharing tracked or staged content. A
22
+ private denylist is required by default and must remain outside the public
23
+ repository.
24
+ - Release candidates are packed once, SHA-256-bound, and the exact audited
25
+ tarball is the artifact sent through npm trusted publishing.
26
+
27
+ Re-run the boundary, disclosure, graph, readiness, and lock checks below after
28
+ updating. If `atelier dev` previously served files without a manifest, generate
29
+ and review the manifest before restarting it.
30
+
8
31
  ## Upgrading to 0.2.0-alpha.4
9
32
 
10
33
  This is a presentation release. There are no contract changes and no runtime
@@ -94,7 +117,7 @@ For registry installs, pin the exact version and record the resolved version
94
117
  in the lockfile:
95
118
 
96
119
  ```bash
97
- npm install --save-dev @mnstry/atelier@0.2.0-alpha.4
120
+ npm install --save-dev @mnstry/atelier@0.2.0-alpha.5
98
121
  npx mnstry-atelier lock write --project ./atelier.project.json
99
122
  ```
100
123
 
@@ -102,7 +125,7 @@ For Git installs, pin the release tag rather than a branch, so the lock file
102
125
  records exactly what was reviewed:
103
126
 
104
127
  ```bash
105
- npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.4"
128
+ npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.5"
106
129
  npx mnstry-atelier lock write --project ./atelier.project.json
107
130
  ```
108
131
 
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "source.html",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "source.html",
3
4
  "title": "Sample Source",
4
5
  "summary": "Neutral non-Markdown source with durable sidecar identity.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "sample-workspace:source-html",
10
11
  "type": "source",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "private",
13
16
  "relations": {}
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "data.json",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "data.json",
3
4
  "title": "Sample dataset",
4
5
  "summary": "Neutral JSON dataset described entirely by its sidecar.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "source-formats:data-json",
10
11
  "type": "source",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "team",
13
16
  "relations": {}
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "logo.png",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "logo.png",
3
4
  "title": "Sample binary asset",
4
5
  "summary": "Four-byte PNG-magic stub; the graph never reads the asset bytes.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "source-formats:logo-png",
10
11
  "type": "artifact",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "sensitive",
13
16
  "relations": {}
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "metrics.csv",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "metrics.csv",
3
4
  "title": "Sample metrics",
4
5
  "summary": "Neutral CSV evidence table described by its sidecar.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "source-formats:metrics-csv",
10
11
  "type": "evidence",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "operator",
13
16
  "relations": {}
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "pipeline.yaml",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "pipeline.yaml",
3
4
  "title": "Sample pipeline",
4
5
  "summary": "Neutral YAML file; atelier never parses it, the sidecar speaks for it.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "source-formats:pipeline-yaml",
10
11
  "type": "source",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "public",
13
16
  "relations": {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnstry/atelier",
3
- "version": "0.2.0-alpha.4",
3
+ "version": "0.2.0-alpha.5",
4
4
  "private": false,
5
5
  "description": "Local toolkit that turns a Git repository into an ontology-governed knowledge graph, enforcement layer, and runtime for people, agents, and tools. No telemetry, service, or account.",
6
6
  "keywords": [
@@ -32,8 +32,10 @@
32
32
  "./readiness-protocols": "./src/readiness-protocols/bundled-pack.mjs",
33
33
  "./server": "./src/server/local-sidecar.mjs",
34
34
  "./harness": "./src/harness/context.mjs",
35
+ "./collaboration": "./src/collaboration/index.mjs",
35
36
  "./support": "./src/support/support-bundle.mjs",
36
37
  "./egress": "./src/egress/forbidden-egress.mjs",
38
+ "./disclosure": "./src/disclosure/content-scan.mjs",
37
39
  "./boundary": "./src/boundary/policy.mjs",
38
40
  "./upgrade": "./src/upgrade/upgrade.mjs",
39
41
  "./attestation": "./src/attestation/sign.mjs",
@@ -48,7 +50,7 @@
48
50
  "contract": "node src/check-atelier-export-contract.mjs",
49
51
  "dry-run": "node src/validate-atelier-export-dry-run.mjs fixtures/atelier-export/sample-studio-offer.v1.json",
50
52
  "test": "node --test test/*.test.mjs",
51
- "syntax:check": "find bin src -name '*.mjs' -print0 | xargs -0 -n1 node --check",
53
+ "syntax:check": "node scripts/check-syntax.mjs",
52
54
  "graph:test": "node --test test/graph.test.mjs test/graph-knowledge-graph.test.mjs test/graph-determinism.test.mjs test/graph-source-formats.test.mjs",
53
55
  "project:test": "node --test test/project.test.mjs test/project-config.test.mjs test/projection-policy.test.mjs test/projection-alignment.test.mjs",
54
56
  "server:security:test": "node --test test/server.test.mjs test/server-security.test.mjs test/server-proposals.test.mjs",
@@ -57,19 +59,24 @@
57
59
  "egress:check": "node bin/atelier.mjs egress check",
58
60
  "readiness:test": "node --test test/readiness.test.mjs test/readiness-summary.test.mjs test/readiness-protocol-contract.test.mjs test/readiness-protocols.test.mjs test/readiness-protocol-runtime.test.mjs",
59
61
  "harness:test": "node --test test/harness.test.mjs test/harness-context.test.mjs",
60
- "boundary:test": "node --test test/boundary-policy-contract.test.mjs test/boundary-guard.test.mjs",
62
+ "collaboration:test": "node --test test/collaboration-ledger.test.mjs test/server-proposals.test.mjs",
63
+ "boundary:test": "node --test test/boundary-policy-contract.test.mjs test/boundary-content-rules.test.mjs test/boundary-guard.test.mjs",
61
64
  "upgrade:test": "node --test test/upgrade-contract.test.mjs test/upgrade.test.mjs",
62
65
  "release:audit": "node scripts/check-release-tarball.mjs",
66
+ "release:candidate": "node scripts/release-candidate.mjs",
63
67
  "repo:check": "node scripts/check-repo-disclosure.mjs",
64
68
  "migrations:check": "node scripts/check-breaking-migrations.mjs",
65
69
  "contract:compat": "node scripts/check-contract-compat.mjs",
70
+ "public-api:compat": "node scripts/check-public-api-compat.mjs",
71
+ "assurance:mutation-smoke": "node --test test/assurance-mutations.test.mjs",
66
72
  "consumer:smoke": "node scripts/consumer-smoke.mjs",
67
73
  "distribution:smoke": "node scripts/distribution-smoke.mjs",
68
- "prepublishOnly": "npm run release:audit && npm run repo:check && npm run migrations:check && npm run contract:compat && npm run syntax:check && npm test && npm run consumer:smoke && npm run distribution:smoke"
74
+ "prepublishOnly": "npm run repo:check && npm run migrations:check && npm run contract:compat && npm run public-api:compat && npm run syntax:check && npm test && npm run assurance:mutation-smoke && npm run release:candidate"
69
75
  },
70
76
  "dependencies": {
71
77
  "ajv": "8.20.0",
72
- "ajv-formats": "3.0.1"
78
+ "ajv-formats": "3.0.1",
79
+ "fast-uri": "3.1.5"
73
80
  },
74
81
  "devDependencies": {
75
82
  "@types/node": "^22.0.0"
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: atelier-local-service
3
+ description: Build or repair a durable loopback-only authoring, review, or preview service in an Atelier-backed repository when local state must survive agent commands and fail safely.
4
+ ---
5
+
6
+ # Atelier local service
7
+
8
+ Use this skill for a consumer-owned service that persists repository-backed
9
+ local state. Do not use it to change `atelier dev` itself or to install an
10
+ operating-system service without explicit authorization.
11
+
12
+ Read `docs/local-services.md` from the installed Atelier package or source
13
+ checkout before changing lifecycle code.
14
+
15
+ ## Boundary first
16
+
17
+ Separate the portable mechanism from the consumer adapter before editing:
18
+
19
+ - Atelier invariants: loopback binding, proven ownership, exact stop, ignored
20
+ mode-0600 state, atomic writes, recoverable browser failure, and tests.
21
+ - Consumer details: service identity, port, commands, paths, schema, content,
22
+ and user-facing language.
23
+
24
+ Never promote consumer names, content, structures, examples, or local paths
25
+ into Atelier. Public tests use invented fixtures.
26
+
27
+ ## Workflow
28
+
29
+ 1. Inspect the existing server, process owner, port, persistence file,
30
+ `.gitignore`, health route, save handler, and tests. Preserve the live draft
31
+ before restarting anything.
32
+ 2. Expose repository-owned `start`, `status`, and `stop` commands. Start may
33
+ detach only because the user needs continuity beyond the launching command.
34
+ 3. Bind to loopback. Pair a random runtime identifier with the PID in both the
35
+ private runtime record and health response. Refuse unowned listeners.
36
+ 4. Keep drafts, runtime metadata, and operational logs ignored and owner-only.
37
+ Do not commit live authoring state.
38
+ 5. Make the UI retain the draft when the service disappears. Show the exact
39
+ restart command, snapshot export, and Retry path instead of a generic error.
40
+ 6. Serialize writes without permanently rejecting the queue after one failed
41
+ operation. Keep conflicts and invalid state fail-closed.
42
+ 7. Prove lifecycle ownership, server-loss recovery, later-save recovery,
43
+ permissions, ignore coverage, and fresh-checkout discoverability.
44
+
45
+ Do not claim durability from a passing request alone. Report separately:
46
+ saved file truth, managed-process truth, browser recovery truth, and the
47
+ remaining OS-restart boundary.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: atelier-public-boundary
3
+ description: Generalize a lesson from a private or tenant implementation into the public Atelier repository without carrying proprietary material across the trust boundary.
4
+ ---
5
+
6
+ # Atelier public boundary
7
+
8
+ Use this skill whenever a public Atelier change is informed by work in a
9
+ private, client, tenant, or internal repository.
10
+
11
+ ## Extract the invariant, not the source
12
+
13
+ 1. State the reusable failure mode or contract without client vocabulary.
14
+ 2. Identify every source-specific name, path, port, field, content structure,
15
+ example, and operational fact. Keep those in the source repository.
16
+ 3. Re-derive the public mechanism against an invented fixture. Neutral wording
17
+ is not enough if the fixture still reproduces a proprietary structure.
18
+ 4. Keep private disclosure patterns in the ignored denylist or CI secret. Do
19
+ not place them in code, tests, docs, branch names, or commit messages.
20
+ 5. Add a regression test for the general control and run an evidence-backed
21
+ defensive review when a guard changes.
22
+
23
+ ## Required gates
24
+
25
+ Before staging, run the repository's disclosure check. After staging, scan the
26
+ staged index with the private denylist, then inspect the exact diff and release
27
+ tarball. A structural-only pass is useful on an untrusted fork but is not a
28
+ complete maintainer verdict.
29
+
30
+ If the private denylist is unavailable, stop short of claiming the public
31
+ boundary is green. Do not replace it with remembered client names.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: atelier-local-service
3
+ description: Build or repair a durable loopback-only authoring, review, or preview service in an Atelier-backed repository when local state must survive agent commands and fail safely.
4
+ ---
5
+
6
+ # Atelier local service
7
+
8
+ Use this skill for a consumer-owned service that persists repository-backed
9
+ local state. Do not use it to change `atelier dev` itself or to install an
10
+ operating-system service without explicit authorization.
11
+
12
+ Read `docs/local-services.md` from the installed Atelier package or source
13
+ checkout before changing lifecycle code.
14
+
15
+ ## Boundary first
16
+
17
+ Separate the portable mechanism from the consumer adapter before editing:
18
+
19
+ - Atelier invariants: loopback binding, proven ownership, exact stop, ignored
20
+ mode-0600 state, atomic writes, recoverable browser failure, and tests.
21
+ - Consumer details: service identity, port, commands, paths, schema, content,
22
+ and user-facing language.
23
+
24
+ Never promote consumer names, content, structures, examples, or local paths
25
+ into Atelier. Public tests use invented fixtures.
26
+
27
+ ## Workflow
28
+
29
+ 1. Inspect the existing server, process owner, port, persistence file,
30
+ `.gitignore`, health route, save handler, and tests. Preserve the live draft
31
+ before restarting anything.
32
+ 2. Expose repository-owned `start`, `status`, and `stop` commands. Start may
33
+ detach only because the user needs continuity beyond the launching command.
34
+ 3. Bind to loopback. Pair a random runtime identifier with the PID in both the
35
+ private runtime record and health response. Refuse unowned listeners.
36
+ 4. Keep drafts, runtime metadata, and operational logs ignored and owner-only.
37
+ Do not commit live authoring state.
38
+ 5. Make the UI retain the draft when the service disappears. Show the exact
39
+ restart command, snapshot export, and Retry path instead of a generic error.
40
+ 6. Serialize writes without permanently rejecting the queue after one failed
41
+ operation. Keep conflicts and invalid state fail-closed.
42
+ 7. Prove lifecycle ownership, server-loss recovery, later-save recovery,
43
+ permissions, ignore coverage, and fresh-checkout discoverability.
44
+
45
+ Do not claim durability from a passing request alone. Report separately:
46
+ saved file truth, managed-process truth, browser recovery truth, and the
47
+ remaining OS-restart boundary.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: atelier-public-boundary
3
+ description: Generalize a lesson from a private or tenant implementation into the public Atelier repository without carrying proprietary material across the trust boundary.
4
+ ---
5
+
6
+ # Atelier public boundary
7
+
8
+ Use this skill whenever a public Atelier change is informed by work in a
9
+ private, client, tenant, or internal repository.
10
+
11
+ ## Extract the invariant, not the source
12
+
13
+ 1. State the reusable failure mode or contract without client vocabulary.
14
+ 2. Identify every source-specific name, path, port, field, content structure,
15
+ example, and operational fact. Keep those in the source repository.
16
+ 3. Re-derive the public mechanism against an invented fixture. Neutral wording
17
+ is not enough if the fixture still reproduces a proprietary structure.
18
+ 4. Keep private disclosure patterns in the ignored denylist or CI secret. Do
19
+ not place them in code, tests, docs, branch names, or commit messages.
20
+ 5. Add a regression test for the general control and run an evidence-backed
21
+ defensive review when a guard changes.
22
+
23
+ ## Required gates
24
+
25
+ Before staging, run the repository's disclosure check. After staging, scan the
26
+ staged index with the private denylist, then inspect the exact diff and release
27
+ tarball. A structural-only pass is useful on an untrusted fork but is not a
28
+ complete maintainer verdict.
29
+
30
+ If the private denylist is unavailable, stop short of claiming the public
31
+ boundary is green. Do not replace it with remembered client names.